Merge branch 'master' of github.com:birdypme/pulumi
This commit is contained in:
commit
370125868d
3
.github/workflows/container-build.yml
vendored
3
.github/workflows/container-build.yml
vendored
|
@ -3,7 +3,6 @@ on:
|
|||
repository_dispatch:
|
||||
types:
|
||||
- docker-build
|
||||
-
|
||||
env:
|
||||
VERSION: ${{ github.event.client_payload.ref }}
|
||||
|
||||
|
@ -76,6 +75,7 @@ jobs:
|
|||
dockerfile: docker/${{ matrix.sdk }}/Dockerfile
|
||||
additional-tags: ${{ env.VERSION }}
|
||||
build-args: PULUMI_VERSION=${{ env.VERSION }}
|
||||
tag-latest: true
|
||||
- uses: meeDamian/sync-readme@v1.0.6
|
||||
name: Sync readme to Docker Hub
|
||||
with:
|
||||
|
@ -106,6 +106,7 @@ jobs:
|
|||
dockerfile: docker/${{ matrix.sdk }}/Dockerfile.${{ matrix.os }}
|
||||
additional-tags: ${{ env.VERSION }}-${{ matrix.os }}
|
||||
build-args: PULUMI_VERSION=${{ env.VERSION }}
|
||||
tag-latest: true
|
||||
|
||||
image-scan:
|
||||
name: scan container images
|
||||
|
|
191
.github/workflows/master.yml
vendored
Normal file
191
.github/workflows/master.yml
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
[ "master", "feature/**", "feature-**" ]
|
||||
paths-ignore:
|
||||
- 'CHANGELOG.md'
|
||||
- 'README.md'
|
||||
|
||||
env:
|
||||
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_PROD_ACCESS_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PULUMI_TEST_OWNER: "moolumi"
|
||||
GO111MODULE: "on"
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NUGET_PUBLISH_KEY: ${{ secrets.NUGET_PUBLISH_KEY }}
|
||||
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
TRAVIS_PUBLISH_PACKAGES: true
|
||||
|
||||
jobs:
|
||||
publish-sdks:
|
||||
name: Publish SDKs
|
||||
runs-on: ubuntu-latest
|
||||
needs: publish-binaries
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.14.x ]
|
||||
python-version: [ 3.7.x ]
|
||||
dotnet-version: [ 3.1.x ]
|
||||
node-version: [ 10.x ]
|
||||
language: [ "nodejs", "python", "dotnet" ]
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Set up DotNet ${{ matrix.dotnet-version }}
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: ${{ matrix.dotnet-version }}
|
||||
- name: Set up Node ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org
|
||||
always-auth: true
|
||||
- name: Install pipenv
|
||||
uses: dschep/install-pipenv-action@v1
|
||||
- name: Install Twine
|
||||
run: python -m pip install pip twine
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Tags
|
||||
run: |
|
||||
git fetch --quiet --prune --unshallow --tags
|
||||
- name: Update path
|
||||
run: |
|
||||
echo "::add-path::${{ runner.temp }}/opt/pulumi/bin"
|
||||
- name: Set Go Dep path
|
||||
run: |
|
||||
echo "::set-env name=PULUMI_GO_DEP_ROOT::$(dirname $(pwd))"
|
||||
- name: Ensure
|
||||
run: |
|
||||
make ensure
|
||||
- name: Publish Packages
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: |
|
||||
make -C sdk/${{ matrix.language}} publish
|
||||
publish-binaries:
|
||||
name: Publish Binaries
|
||||
runs-on: macos-latest
|
||||
needs: build-and-test
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Tags
|
||||
run: |
|
||||
git fetch --quiet --prune --unshallow --tags
|
||||
- name: Install pulumictl
|
||||
uses: jaxxstorm/action-install-gh-release@6277ebec57d2f9283d245d365f0b05bcc23d85e0
|
||||
with:
|
||||
repo: pulumi/pulumictl
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-region: us-east-2
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
role-duration-seconds: 3600
|
||||
role-external-id: upload-pulumi-release
|
||||
role-session-name: pulumi@githubActions
|
||||
role-to-assume: ${{ secrets.AWS_UPLOAD_ROLE_ARN }}
|
||||
- name: Set PreRelease Version
|
||||
run: echo "::set-env name=GORELEASER_CURRENT_TAG::v$(pulumictl get version --language generic -o)"
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: -f .goreleaser.prerelease.yml --rm-dist --skip-validate
|
||||
lint:
|
||||
container: golangci/golangci-lint:latest
|
||||
name: Lint ${{ matrix.directory }}
|
||||
strategy:
|
||||
matrix:
|
||||
directory: [ sdk, pkg, tests ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Lint ${{ matrix.directory }}
|
||||
run: |
|
||||
cd ${{ matrix.directory }} && golangci-lint run -c ../.golangci.yml
|
||||
build-and-test:
|
||||
name: Build & Test
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [ ubuntu-latest, macos-latest ]
|
||||
go-version: [1.14.x]
|
||||
python-version: [ 3.7.x ]
|
||||
dotnet-version: [ 3.1.x ]
|
||||
node-version: [ 10.x ]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Set up DotNet ${{ matrix.dotnet-version }}
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: ${{ matrix.dotnet-version }}
|
||||
- name: Set up Node ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install pipenv
|
||||
uses: dschep/install-pipenv-action@v1
|
||||
- name: Setup git
|
||||
run: |
|
||||
git config --global user.email "you@example.com"
|
||||
git config --global user.name "Your Name"
|
||||
- name: Update path
|
||||
run: |
|
||||
echo "::add-path::${{ runner.temp }}/opt/pulumi/bin"
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Tags
|
||||
run: |
|
||||
git fetch --quiet --prune --unshallow --tags
|
||||
- name: Set Go Dep path
|
||||
run: |
|
||||
echo "::set-env name=PULUMI_GO_DEP_ROOT::$(dirname $(pwd))"
|
||||
- name: Ensure
|
||||
run: |
|
||||
make ensure
|
||||
- name: Dist
|
||||
run: |
|
||||
make dist
|
||||
env:
|
||||
PULUMI_NODE_MODULES: ${{ runner.temp }}/opt/pulumi/node_modules
|
||||
PULUMI_LOCAL_NUGET: ${{ runner.temp }}/opt/pulumi/nuget
|
||||
PULUMI_ROOT: ${{ runner.temp }}/opt/pulumi
|
||||
- name: Install
|
||||
run: |
|
||||
make install_all
|
||||
env:
|
||||
PULUMI_NODE_MODULES: ${{ runner.temp }}/opt/pulumi/node_modules
|
||||
PULUMI_LOCAL_NUGET: ${{ runner.temp }}/opt/pulumi/nuget
|
||||
PULUMI_ROOT: ${{ runner.temp }}/opt/pulumi
|
||||
- name: Test
|
||||
run: |
|
||||
make test_all
|
||||
env:
|
||||
PULUMI_NODE_MODULES: ${{ runner.temp }}/opt/pulumi/node_modules
|
||||
PULUMI_LOCAL_NUGET: ${{ runner.temp }}/opt/pulumi/nuget
|
||||
PULUMI_ROOT: ${{ runner.temp }}/opt/pulumi
|
||||
|
||||
|
227
.github/workflows/release.yml
vendored
Normal file
227
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,227 @@
|
|||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*.*.*
|
||||
paths-ignore:
|
||||
- 'CHANGELOG.md'
|
||||
- 'README.md'
|
||||
env:
|
||||
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_PROD_ACCESS_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PULUMI_TEST_OWNER: "moolumi"
|
||||
GO111MODULE: "on"
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NUGET_PUBLISH_KEY: ${{ secrets.NUGET_PUBLISH_KEY }}
|
||||
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
TRAVIS_PUBLISH_PACKAGES: true
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
name: Build Docker Images
|
||||
runs-on: ubuntu-latest
|
||||
needs: publish-sdks
|
||||
steps:
|
||||
- name: Install Pulumictl
|
||||
uses: jaxxstorm/action-install-gh-release@release/v1-alpha
|
||||
with:
|
||||
repo: pulumi/pulumictl
|
||||
- name: Set version
|
||||
run: |
|
||||
echo "::set-env name=NPM_VERSION::$(./scripts/get-version HEAD)"
|
||||
- name: Trigger Docker Build
|
||||
run: ./scripts/build-docker.sh" "${NPM_VERSION}" --publish
|
||||
docs:
|
||||
name: Build Package Docs
|
||||
runs-on: ubuntu-latest
|
||||
needs: publish-sdks
|
||||
steps:
|
||||
- name: Checkout Scripts Repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: ci-scripts
|
||||
repository: pulumi/scripts
|
||||
- name: Trigger Docs Build
|
||||
run: |
|
||||
./ci-scripts/ci/build-package-docs.sh "pulumi"
|
||||
homebrew:
|
||||
name: Update Homebrew
|
||||
runs-on: macos-latest
|
||||
needs: publish-sdks
|
||||
steps:
|
||||
- name : Bump Homebrew Formula
|
||||
uses: dawidd6/action-homebrew-bump-formula@v3
|
||||
with:
|
||||
token: ${{ secrets.PULUMI_BOT_TOKEN }}
|
||||
formula: pulumi
|
||||
publish-sdks:
|
||||
name: Publish SDKs
|
||||
runs-on: ubuntu-latest
|
||||
needs: publish-binaries
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.14.x ]
|
||||
python-version: [ 3.7.x ]
|
||||
dotnet-version: [ 3.1.x ]
|
||||
node-version: [ 10.x ]
|
||||
language: [ "nodejs", "python", "dotnet" ]
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Set up DotNet ${{ matrix.dotnet-version }}
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: ${{ matrix.dotnet-version }}
|
||||
- name: Set up Node ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org
|
||||
always-auth: true
|
||||
- name: Install pipenv
|
||||
uses: dschep/install-pipenv-action@v1
|
||||
- name: Install Twine
|
||||
run: python -m pip install pip twine
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Tags
|
||||
run: |
|
||||
git fetch --quiet --prune --unshallow --tags
|
||||
- name: Update path
|
||||
run: |
|
||||
echo "::add-path::${{ runner.temp }}/opt/pulumi/bin"
|
||||
- name: Set Go Dep path
|
||||
run: |
|
||||
echo "::set-env name=PULUMI_GO_DEP_ROOT::$(dirname $(pwd))"
|
||||
- name: Ensure
|
||||
run: |
|
||||
make ensure
|
||||
- name: Publish Packages
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: |
|
||||
make -C sdk/${{ matrix.language}} publish
|
||||
publish-binaries:
|
||||
name: Publish Binaries
|
||||
runs-on: macos-latest
|
||||
needs: build-and-test
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Tags
|
||||
run: |
|
||||
git fetch --quiet --prune --unshallow --tags
|
||||
- name: Install pulumictl
|
||||
uses: jaxxstorm/action-install-gh-release@6277ebec57d2f9283d245d365f0b05bcc23d85e0
|
||||
with:
|
||||
repo: pulumi/pulumictl
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-region: us-east-2
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
role-duration-seconds: 3600
|
||||
role-external-id: upload-pulumi-release
|
||||
role-session-name: pulumi@githubActions
|
||||
role-to-assume: ${{ secrets.AWS_UPLOAD_ROLE_ARN }}
|
||||
- name: Set PreRelease Version
|
||||
run: echo "::set-env name=GORELEASER_CURRENT_TAG::v$(pulumictl get version --language generic -o)"
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: -f .goreleaser.yml --rm-dist
|
||||
lint:
|
||||
container: golangci/golangci-lint:latest
|
||||
name: Lint ${{ matrix.directory }}
|
||||
strategy:
|
||||
matrix:
|
||||
directory: [ sdk, pkg, tests ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Lint ${{ matrix.directory }}
|
||||
run: |
|
||||
cd ${{ matrix.directory }} && golangci-lint run -c ../.golangci.yml
|
||||
build-and-test:
|
||||
name: Build & Test
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [ ubuntu-latest, macos-latest ]
|
||||
go-version: [1.14.x]
|
||||
python-version: [ 3.7.x ]
|
||||
dotnet-version: [ 3.1.x ]
|
||||
node-version: [ 10.x ]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Set up DotNet ${{ matrix.dotnet-version }}
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: ${{ matrix.dotnet-version }}
|
||||
- name: Set up Node ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install pipenv
|
||||
uses: dschep/install-pipenv-action@v1
|
||||
- name: Setup git
|
||||
run: |
|
||||
git config --global user.email "you@example.com"
|
||||
git config --global user.name "Your Name"
|
||||
- name: Update path
|
||||
run: |
|
||||
echo "::add-path::${{ runner.temp }}/opt/pulumi/bin"
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Tags
|
||||
run: |
|
||||
git fetch --quiet --prune --unshallow --tags
|
||||
- name: Set Go Dep path
|
||||
run: |
|
||||
echo "::set-env name=PULUMI_GO_DEP_ROOT::$(dirname $(pwd))"
|
||||
- name: Ensure
|
||||
run: |
|
||||
make ensure
|
||||
- name: Dist
|
||||
run: |
|
||||
make dist
|
||||
env:
|
||||
PULUMI_NODE_MODULES: ${{ runner.temp }}/opt/pulumi/node_modules
|
||||
PULUMI_LOCAL_NUGET: ${{ runner.temp }}/opt/pulumi/nuget
|
||||
PULUMI_ROOT: ${{ runner.temp }}/opt/pulumi
|
||||
- name: Install
|
||||
run: |
|
||||
make install_all
|
||||
env:
|
||||
PULUMI_NODE_MODULES: ${{ runner.temp }}/opt/pulumi/node_modules
|
||||
PULUMI_LOCAL_NUGET: ${{ runner.temp }}/opt/pulumi/nuget
|
||||
PULUMI_ROOT: ${{ runner.temp }}/opt/pulumi
|
||||
- name: Test
|
||||
run: |
|
||||
make test_all
|
||||
env:
|
||||
PULUMI_NODE_MODULES: ${{ runner.temp }}/opt/pulumi/node_modules
|
||||
PULUMI_LOCAL_NUGET: ${{ runner.temp }}/opt/pulumi/nuget
|
||||
PULUMI_ROOT: ${{ runner.temp }}/opt/pulumi
|
||||
|
||||
|
171
.goreleaser.prerelease.yml
Normal file
171
.goreleaser.prerelease.yml
Normal file
|
@ -0,0 +1,171 @@
|
|||
# This is an example goreleaser.yaml file with some sane defaults.
|
||||
# Make sure to check the documentation at http://goreleaser.com
|
||||
dist: goreleaser
|
||||
project_name: pulumi
|
||||
before:
|
||||
hooks:
|
||||
- cd sdk && go mod tidy
|
||||
- cd sdk && go mod download
|
||||
- cd pkg && go mod tidy
|
||||
- cd pkg && go mod download
|
||||
blobs:
|
||||
- bucket: get.pulumi.com
|
||||
folder: releases/sdk/
|
||||
ids:
|
||||
- pulumi-unix
|
||||
- pulumi-windows
|
||||
provider: s3
|
||||
region: us-west-2
|
||||
changelog:
|
||||
skip: true
|
||||
release:
|
||||
disable: true
|
||||
builds:
|
||||
# UNIX builds
|
||||
- id: pulumi-unix
|
||||
binary: pulumi
|
||||
dir: pkg
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./cmd/pulumi
|
||||
- id: pulumi-language-nodejs-unix
|
||||
binary: pulumi-language-nodejs
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./nodejs/cmd/pulumi-language-nodejs
|
||||
- id: pulumi-language-python-unix
|
||||
binary: pulumi-language-python
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./python/cmd/pulumi-language-python
|
||||
- id: pulumi-language-dotnet-unix
|
||||
binary: pulumi-language-dotnet
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./dotnet/cmd/pulumi-language-dotnet
|
||||
- id: pulumi-language-go-unix
|
||||
binary: pulumi-language-go
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./go/pulumi-language-go
|
||||
|
||||
# Windows builds
|
||||
- id: pulumi-windows
|
||||
binary: pulumi
|
||||
dir: pkg
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- windows
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./cmd/pulumi
|
||||
- id: pulumi-language-nodejs-windows
|
||||
binary: pulumi-language-nodejs
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- windows
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./nodejs/cmd/pulumi-language-nodejs
|
||||
- id: pulumi-language-python-windows
|
||||
binary: pulumi-language-python
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- windows
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./python/cmd/pulumi-language-python
|
||||
- id: pulumi-language-dotnet-windows
|
||||
binary: pulumi-language-dotnet
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- windows
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./dotnet/cmd/pulumi-language-dotnet
|
||||
- id: pulumi-language-go-windows
|
||||
binary: pulumi-language-go
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- windows
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./go/pulumi-language-go
|
||||
archives:
|
||||
- id: pulumi-unix
|
||||
builds:
|
||||
- pulumi-language-dotnet-unix
|
||||
- pulumi-language-go-unix
|
||||
- pulumi-language-python-unix
|
||||
- pulumi-language-nodejs-unix
|
||||
- pulumi-unix
|
||||
replacements:
|
||||
amd64: x64
|
||||
files:
|
||||
- sdk/nodejs/dist/pulumi-resource-pulumi-nodejs
|
||||
- sdk/python/dist/pulumi-resource-pulumi-python
|
||||
- sdk/nodejs/dist/pulumi-analyzer-policy
|
||||
- sdk/python/dist/pulumi-analyzer-policy-python
|
||||
- sdk/python/cmd/pulumi-language-python-exec
|
||||
name_template: "{{ .ProjectName }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}"
|
||||
- id: pulumi-windows
|
||||
builds:
|
||||
- pulumi-language-dotnet-windows
|
||||
- pulumi-language-go-windows
|
||||
- pulumi-language-python-windows
|
||||
- pulumi-language-nodejs-windows
|
||||
- pulumi-windows
|
||||
replacements:
|
||||
amd64: x64
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
files:
|
||||
- sdk/nodejs/dist/pulumi-resource-pulumi-nodejs.cmd
|
||||
- sdk/python/dist/pulumi-resource-pulumi-python.cmd
|
||||
- sdk/nodejs/dist/pulumi-analyzer-policy.cmd
|
||||
- sdk/python/dist/pulumi-analyzer-policy-python.cmd
|
||||
- sdk/python/cmd/pulumi-language-python-exec
|
||||
name_template: "{{ .ProjectName }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}"
|
||||
snapshot:
|
||||
name_template: "{{ .Version }}-SNAPSHOT"
|
||||
checksum:
|
||||
name_template: "{{ .ProjectName }}-{{ .Version }}-checksums.txt"
|
159
.goreleaser.yml
Normal file
159
.goreleaser.yml
Normal file
|
@ -0,0 +1,159 @@
|
|||
# This is an example goreleaser.yaml file with some sane defaults.
|
||||
# Make sure to check the documentation at http://goreleaser.com
|
||||
dist: goreleaser
|
||||
project_name: pulumi
|
||||
before:
|
||||
hooks:
|
||||
- cd sdk && go mod tidy
|
||||
- cd sdk && go mod download
|
||||
- cd pkg && go mod tidy
|
||||
- cd pkg && go mod download
|
||||
builds:
|
||||
# UNIX builds
|
||||
- id: pulumi-unix
|
||||
binary: pulumi
|
||||
dir: pkg
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./cmd/pulumi
|
||||
- id: pulumi-language-nodejs-unix
|
||||
binary: pulumi-language-nodejs
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./nodejs/cmd/pulumi-language-nodejs
|
||||
- id: pulumi-language-python-unix
|
||||
binary: pulumi-language-python
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./python/cmd/pulumi-language-python
|
||||
- id: pulumi-language-dotnet-unix
|
||||
binary: pulumi-language-dotnet
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./dotnet/cmd/pulumi-language-dotnet
|
||||
- id: pulumi-language-go-unix
|
||||
binary: pulumi-language-go
|
||||
dir: sdk
|
||||
goarch:
|
||||
- amd64
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
ldflags:
|
||||
- github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
main: ./go/pulumi-language-go
|
||||
|
||||
# Windows builds
|
||||
#- id: pulumi-windows
|
||||
# binary: pulumi
|
||||
# dir: pkg
|
||||
# goarch:
|
||||
# - amd64
|
||||
# goos:
|
||||
# - windows
|
||||
# ldflags:
|
||||
# - github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
# main: ./cmd/pulumi
|
||||
#- id: pulumi-language-nodejs-windows
|
||||
# binary: pulumi-language-nodejs
|
||||
# dir: sdk
|
||||
# goarch:
|
||||
# - amd64
|
||||
# goos:
|
||||
# - windows
|
||||
# ldflags:
|
||||
# - github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
# main: ./nodejs/cmd/pulumi-language-nodejs
|
||||
#- id: pulumi-language-python-windows
|
||||
# binary: pulumi-language-python
|
||||
# dir: sdk
|
||||
# goarch:
|
||||
# - amd64
|
||||
# goos:
|
||||
# - windows
|
||||
# ldflags:
|
||||
# - github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
# main: ./python/cmd/pulumi-language-python
|
||||
#- id: pulumi-language-dotnet-windows
|
||||
# binary: pulumi-language-dotnet
|
||||
# dir: sdk
|
||||
# goarch:
|
||||
# - amd64
|
||||
# goos:
|
||||
# - windows
|
||||
# ldflags:
|
||||
# - github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
# main: ./dotnet/cmd/pulumi-language-dotnet
|
||||
#- id: pulumi-language-go-windows
|
||||
# binary: pulumi-language-go
|
||||
# dir: sdk
|
||||
# goarch:
|
||||
# - amd64
|
||||
# goos:
|
||||
# - windows
|
||||
# ldflags:
|
||||
# - github.com/pulumi/pulumi/pkg/v2/version.Version={{.Tag}}
|
||||
# main: ./go/pulumi-language-go
|
||||
archives:
|
||||
- id: pulumi-unix
|
||||
builds:
|
||||
- pulumi-language-dotnet-unix
|
||||
- pulumi-language-go-unix
|
||||
- pulumi-language-python-unix
|
||||
- pulumi-language-nodejs-unix
|
||||
- pulumi-unix
|
||||
replacements:
|
||||
amd64: x64
|
||||
files:
|
||||
- sdk/nodejs/dist/pulumi-resource-pulumi-nodejs
|
||||
- sdk/python/dist/pulumi-resource-pulumi-python
|
||||
- sdk/nodejs/dist/pulumi-analyzer-policy
|
||||
- sdk/python/dist/pulumi-analyzer-policy-python
|
||||
- sdk/python/cmd/pulumi-language-python-exec
|
||||
name_template: "{{ .ProjectName }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}"
|
||||
#- id: pulumi-windows
|
||||
# builds:
|
||||
# - pulumi-language-dotnet-windows
|
||||
# - pulumi-language-go-windows
|
||||
# - pulumi-language-python-windows
|
||||
# - pulumi-language-nodejs-windows
|
||||
# - pulumi-windows
|
||||
# replacements:
|
||||
# amd64: x64
|
||||
# format_overrides:
|
||||
# - goos: windows
|
||||
# format: zip
|
||||
# files:
|
||||
# - sdk/nodejs/dist/pulumi-resource-pulumi-nodejs.cmd
|
||||
# - sdk/python/dist/pulumi-resource-pulumi-python.cmd
|
||||
# - sdk/nodejs/dist/pulumi-analyzer-policy.cmd
|
||||
# - sdk/python/dist/pulumi-analyzer-policy-python.cmd
|
||||
# - sdk/python/cmd/pulumi-language-python-exec
|
||||
# name_template: "{{ .ProjectName }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}"
|
||||
snapshot:
|
||||
name_template: "{{ .Version }}-SNAPSHOT"
|
||||
checksum:
|
||||
name_template: "{{ .ProjectName }}-{{ .Version }}-checksums.txt"
|
40
.travis.yml
40
.travis.yml
|
@ -1,40 +0,0 @@
|
|||
if: branch = master OR branch =~ ^features/ OR branch =~ ^feature- OR branch =~ ^feature/ OR tag =~ ^v\d+.*
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: NODE_VERSION=v12.1.0 TRAVIS_PUBLISH_PACKAGES=true
|
||||
- if: type IN (cron, push)
|
||||
os: osx
|
||||
env: NODE_VERSION=v10.15.3
|
||||
- if: type = cron
|
||||
os: linux
|
||||
env: NODE_VERSION=v13.11.0
|
||||
language: go
|
||||
go: 1.14.x
|
||||
sudo: true
|
||||
git:
|
||||
depth: false
|
||||
before_install:
|
||||
- |
|
||||
if [ "$TRAVIS_PULL_REQUEST_SLUG" != "pulumi/pulumi" ];
|
||||
then
|
||||
echo "Community PR - Not decrypting gcp credentials";
|
||||
else
|
||||
echo "Decrypting gcp credentials"
|
||||
openssl aes-256-cbc -K $encrypted_342342ee5e49_key -iv $encrypted_342342ee5e49_iv -in gcp-credentials.json.enc -out gcp-credentials.json -d
|
||||
fi
|
||||
- git clone https://github.com/pulumi/scripts ${GOPATH}/src/github.com/pulumi/scripts
|
||||
- source ${GOPATH}/src/github.com/pulumi/scripts/ci/prepare-environment.sh
|
||||
- source ${PULUMI_SCRIPTS}/ci/keep-failed-tests.sh
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then ulimit -n 2048; fi
|
||||
install:
|
||||
- source ${PULUMI_SCRIPTS}/ci/install-common-toolchain.sh
|
||||
before_script:
|
||||
- "${PULUMI_SCRIPTS}/ci/ensure-dependencies"
|
||||
script:
|
||||
- make travis_${TRAVIS_EVENT_TYPE}
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./scripts/update_homebrew.sh; fi
|
||||
after_failure:
|
||||
- "${PULUMI_SCRIPTS}/ci/upload-failed-tests"
|
||||
notifications:
|
||||
webhooks: https://zlmgkhmhjc.execute-api.us-west-2.amazonaws.com/stage/travis
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -5,6 +5,20 @@ CHANGELOG
|
|||
|
||||
_(None)_
|
||||
|
||||
## 2.11.0 (2020-09-30)
|
||||
|
||||
- Do not oversimplify types for display when running an update or preview.
|
||||
[#5440](https://github.com/pulumi/pulumi/pull/5440)
|
||||
|
||||
- Pulumi Windows CLI now uploads all VCS information to console
|
||||
(fixes [#5014](https://github.com/pulumi/pulumi/issues/5014))
|
||||
[#5406](https://github.com/pulumi/pulumi/pull/5406)
|
||||
|
||||
- .NET SDK: Support `Output<object>` for resource output properties
|
||||
(fixes [#5446](https://github.com/pulumi/pulumi/issues/5446))
|
||||
[#5465](https://github.com/pulumi/pulumi/pull/5465)
|
||||
|
||||
|
||||
## 2.10.2 (2020-09-21)
|
||||
|
||||
- [sdk/go] Add missing Version field to invokeOptions
|
||||
|
@ -12,7 +26,7 @@ _(None)_
|
|||
|
||||
- Add `pulumi console` command which opens the currently selected stack in the Pulumi console.
|
||||
[#5368](https://github.com/pulumi/pulumi/pull/5368)
|
||||
|
||||
|
||||
- Python SDK: Cast numbers intended to be integers to `int`.
|
||||
[#5419](https://github.com/pulumi/pulumi/pull/5419)
|
||||
|
||||
|
|
4
Makefile
4
Makefile
|
@ -100,7 +100,9 @@ test_containers_cron:
|
|||
# The travis_* targets are entrypoints for CI.
|
||||
.PHONY: travis_cron travis_push travis_pull_request travis_api
|
||||
travis_cron: install dist all
|
||||
travis_push: install dist publish_tgz only_test publish_packages
|
||||
travis_push:
|
||||
$(call STEP_MESSAGE)
|
||||
@echo moved to GitHub Actions
|
||||
travis_pull_request:
|
||||
$(call STEP_MESSAGE)
|
||||
@echo moved to GitHub Actions
|
||||
|
|
4
dist/pulumi/Dockerfile
vendored
4
dist/pulumi/Dockerfile
vendored
|
@ -4,8 +4,8 @@ LABEL "repository"="https://github.com/pulumi/pulumi"
|
|||
LABEL "homepage"="https://pulumi.com/"
|
||||
LABEL "maintainer"="Pulumi Team <team@pulumi.com>"
|
||||
|
||||
ENV GOLANG_VERSION 1.13.10
|
||||
ENV GOLANG_SHA256 8a4cbc9f2b95d114c38f6cbe94a45372d48c604b707db2057c787398dfbf8e7f
|
||||
ENV GOLANG_VERSION 1.14.9
|
||||
ENV GOLANG_SHA256 f0d26ff572c72c9823ae752d3c81819a81a60c753201f51f89637482531c110a
|
||||
|
||||
# Install deps all in one step
|
||||
RUN apt-get update -y && \
|
||||
|
|
|
@ -9,7 +9,7 @@ FROM ${PULUMI_IMAGE}:${PULUMI_VERSION} as pulumi
|
|||
FROM ubuntu:bionic AS builder
|
||||
|
||||
# Set go versions
|
||||
ARG RUNTIME_VERSION=1.14.4
|
||||
ARG RUNTIME_VERSION=1.14.9
|
||||
|
||||
WORKDIR /golang
|
||||
RUN apt-get update -y && \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Must be defined first
|
||||
ARG PULUMI_VERSION=latest
|
||||
ARG PULUMI_IMAGE=pulumi/pulumi-base
|
||||
ARG RUNTIME_VERSION=1.14.4
|
||||
ARG RUNTIME_VERSION=1.14.9
|
||||
FROM ${PULUMI_IMAGE}:${PULUMI_VERSION}-alpine as pulumi
|
||||
|
||||
# The runtime container
|
||||
|
|
|
@ -9,7 +9,7 @@ FROM ${PULUMI_IMAGE}:${PULUMI_VERSION} as pulumi
|
|||
FROM registry.access.redhat.com/ubi8/ubi-minimal:latest AS builder
|
||||
|
||||
# Set go versions
|
||||
ARG RUNTIME_VERSION=1.14.4
|
||||
ARG RUNTIME_VERSION=1.14.9
|
||||
|
||||
WORKDIR /golang
|
||||
RUN microdnf install -y \
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -167,16 +166,44 @@ type ProgressDisplay struct {
|
|||
}
|
||||
|
||||
var (
|
||||
// simple regex to take our names like "aws:function:Function" and convert to
|
||||
// "aws:Function"
|
||||
typeNameRegex = regexp.MustCompile("^(.*):(.*)/(.*):(.*)$")
|
||||
// policyPayloads is a collection of policy violation events for a single resource.
|
||||
policyPayloads []engine.PolicyViolationEventPayload
|
||||
)
|
||||
|
||||
func camelCase(s string) string {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
runes := []rune(s)
|
||||
runes[0] = unicode.ToLower(runes[0])
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func simplifyTypeName(typ tokens.Type) string {
|
||||
typeString := string(typ)
|
||||
return typeNameRegex.ReplaceAllString(typeString, "$1:$2:$4")
|
||||
|
||||
components := strings.Split(typeString, ":")
|
||||
if len(components) != 3 {
|
||||
return typeString
|
||||
}
|
||||
pkg, module, name := components[0], components[1], components[2]
|
||||
|
||||
if len(name) == 0 {
|
||||
return typeString
|
||||
}
|
||||
|
||||
lastSlashInModule := strings.LastIndexByte(module, '/')
|
||||
if lastSlashInModule == -1 {
|
||||
return typeString
|
||||
}
|
||||
file := module[lastSlashInModule+1:]
|
||||
|
||||
if file != camelCase(name) {
|
||||
return typeString
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v:%v:%v", pkg, module[:lastSlashInModule], name)
|
||||
}
|
||||
|
||||
// getEventUrn returns the resource URN associated with an event, or the empty URN if this is not an
|
||||
|
|
31
pkg/codegen/internal/test/testdata/simple-resource-schema/argFunction.ts
vendored
Normal file
31
pkg/codegen/internal/test/testdata/simple-resource-schema/argFunction.ts
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// *** WARNING: this file was generated by test. ***
|
||||
// *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as inputs from "./types/input";
|
||||
import * as outputs from "./types/output";
|
||||
import * as utilities from "./utilities";
|
||||
|
||||
import {Resource} from "./index";
|
||||
|
||||
export function argFunction(args?: ArgFunctionArgs, opts?: pulumi.InvokeOptions): Promise<ArgFunctionResult> {
|
||||
args = args || {};
|
||||
if (!opts) {
|
||||
opts = {}
|
||||
}
|
||||
|
||||
if (!opts.version) {
|
||||
opts.version = utilities.getVersion();
|
||||
}
|
||||
return pulumi.runtime.invoke("example::argFunction", {
|
||||
"arg1": args.arg1,
|
||||
}, opts);
|
||||
}
|
||||
|
||||
export interface ArgFunctionArgs {
|
||||
readonly arg1?: Resource;
|
||||
}
|
||||
|
||||
export interface ArgFunctionResult {
|
||||
readonly result?: Resource;
|
||||
}
|
56
pkg/codegen/internal/test/testdata/simple-resource-schema/otherResource.ts
vendored
Normal file
56
pkg/codegen/internal/test/testdata/simple-resource-schema/otherResource.ts
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
// *** WARNING: this file was generated by test. ***
|
||||
// *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as utilities from "./utilities";
|
||||
|
||||
import {Resource} from "./index";
|
||||
|
||||
export class OtherResource extends pulumi.ComponentResource {
|
||||
/** @internal */
|
||||
public static readonly __pulumiType = 'example::OtherResource';
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an instance of OtherResource. This is designed to work even
|
||||
* when multiple copies of the Pulumi SDK have been loaded into the same process.
|
||||
*/
|
||||
public static isInstance(obj: any): obj is OtherResource {
|
||||
if (obj === undefined || obj === null) {
|
||||
return false;
|
||||
}
|
||||
return obj['__pulumiType'] === OtherResource.__pulumiType;
|
||||
}
|
||||
|
||||
public readonly foo!: pulumi.Output<Resource | undefined>;
|
||||
|
||||
/**
|
||||
* Create a OtherResource resource with the given unique name, arguments, and options.
|
||||
*
|
||||
* @param name The _unique_ name of the resource.
|
||||
* @param args The arguments to use to populate this resource's properties.
|
||||
* @param opts A bag of options that control this resource's behavior.
|
||||
*/
|
||||
constructor(name: string, args?: OtherResourceArgs, opts?: pulumi.ComponentResourceOptions) {
|
||||
let inputs: pulumi.Inputs = {};
|
||||
if (!(opts && opts.id)) {
|
||||
inputs["foo"] = args ? args.foo : undefined;
|
||||
} else {
|
||||
inputs["foo"] = undefined /*out*/;
|
||||
}
|
||||
if (!opts) {
|
||||
opts = {}
|
||||
}
|
||||
|
||||
if (!opts.version) {
|
||||
opts.version = utilities.getVersion();
|
||||
}
|
||||
super(OtherResource.__pulumiType, name, inputs, opts, true /*remote*/);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The set of arguments for constructing a OtherResource resource.
|
||||
*/
|
||||
export interface OtherResourceArgs {
|
||||
readonly foo?: pulumi.Input<Resource>;
|
||||
}
|
54
pkg/codegen/internal/test/testdata/simple-resource-schema/pulumi_example/arg_function.py
vendored
Normal file
54
pkg/codegen/internal/test/testdata/simple-resource-schema/pulumi_example/arg_function.py
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import warnings
|
||||
import pulumi
|
||||
import pulumi.runtime
|
||||
from typing import Any, Mapping, Optional, Sequence, Union
|
||||
from . import _utilities, _tables
|
||||
from . import Resource
|
||||
|
||||
__all__ = [
|
||||
'ArgFunctionResult',
|
||||
'AwaitableArgFunctionResult',
|
||||
'arg_function',
|
||||
]
|
||||
|
||||
@pulumi.output_type
|
||||
class ArgFunctionResult:
|
||||
def __init__(__self__, result=None):
|
||||
if result and not isinstance(result, Resource):
|
||||
raise TypeError("Expected argument 'result' to be a Resource")
|
||||
pulumi.set(__self__, "result", result)
|
||||
|
||||
@property
|
||||
@pulumi.getter
|
||||
def result(self) -> Optional['Resource']:
|
||||
return pulumi.get(self, "result")
|
||||
|
||||
|
||||
class AwaitableArgFunctionResult(ArgFunctionResult):
|
||||
# pylint: disable=using-constant-test
|
||||
def __await__(self):
|
||||
if False:
|
||||
yield self
|
||||
return ArgFunctionResult(
|
||||
result=self.result)
|
||||
|
||||
|
||||
def arg_function(arg1: Optional['Resource'] = None,
|
||||
opts: Optional[pulumi.InvokeOptions] = None) -> AwaitableArgFunctionResult:
|
||||
"""
|
||||
Use this data source to access information about an existing resource.
|
||||
"""
|
||||
__args__ = dict()
|
||||
__args__['arg1'] = arg1
|
||||
if opts is None:
|
||||
opts = pulumi.InvokeOptions()
|
||||
if opts.version is None:
|
||||
opts.version = _utilities.get_version()
|
||||
__ret__ = pulumi.runtime.invoke('example::argFunction', __args__, opts=opts, typ=ArgFunctionResult).value
|
||||
|
||||
return AwaitableArgFunctionResult(
|
||||
result=__ret__.result)
|
65
pkg/codegen/internal/test/testdata/simple-resource-schema/pulumi_example/other_resource.py
vendored
Normal file
65
pkg/codegen/internal/test/testdata/simple-resource-schema/pulumi_example/other_resource.py
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import warnings
|
||||
import pulumi
|
||||
import pulumi.runtime
|
||||
from typing import Any, Mapping, Optional, Sequence, Union
|
||||
from . import _utilities, _tables
|
||||
from . import Resource
|
||||
|
||||
__all__ = ['OtherResource']
|
||||
|
||||
|
||||
class OtherResource(pulumi.ComponentResource):
|
||||
def __init__(__self__,
|
||||
resource_name: str,
|
||||
opts: Optional[pulumi.ResourceOptions] = None,
|
||||
foo: Optional[pulumi.Input['Resource']] = None,
|
||||
__props__=None,
|
||||
__name__=None,
|
||||
__opts__=None):
|
||||
"""
|
||||
Create a OtherResource resource with the given unique name, props, and options.
|
||||
:param str resource_name: The name of the resource.
|
||||
:param pulumi.ResourceOptions opts: Options for the resource.
|
||||
"""
|
||||
if __name__ is not None:
|
||||
warnings.warn("explicit use of __name__ is deprecated", DeprecationWarning)
|
||||
resource_name = __name__
|
||||
if __opts__ is not None:
|
||||
warnings.warn("explicit use of __opts__ is deprecated, use 'opts' instead", DeprecationWarning)
|
||||
opts = __opts__
|
||||
if opts is None:
|
||||
opts = pulumi.ResourceOptions()
|
||||
if not isinstance(opts, pulumi.ResourceOptions):
|
||||
raise TypeError('Expected resource options to be a ResourceOptions instance')
|
||||
if opts.version is None:
|
||||
opts.version = _utilities.get_version()
|
||||
if opts.id is not None:
|
||||
raise ValueError('ComponentResource classes do not support opts.id')
|
||||
else:
|
||||
if __props__ is not None:
|
||||
raise TypeError('__props__ is only valid when passed in combination with a valid opts.id to get an existing resource')
|
||||
__props__ = dict()
|
||||
|
||||
__props__['foo'] = foo
|
||||
super(OtherResource, __self__).__init__(
|
||||
'example::OtherResource',
|
||||
resource_name,
|
||||
__props__,
|
||||
opts,
|
||||
remote=True)
|
||||
|
||||
@property
|
||||
@pulumi.getter
|
||||
def foo(self) -> pulumi.Output[Optional['Resource']]:
|
||||
return pulumi.get(self, "foo")
|
||||
|
||||
def translate_output_property(self, prop):
|
||||
return _tables.CAMEL_TO_SNAKE_CASE_TABLE.get(prop) or prop
|
||||
|
||||
def translate_input_property(self, prop):
|
||||
return _tables.SNAKE_TO_CAMEL_CASE_TABLE.get(prop) or prop
|
||||
|
79
pkg/codegen/internal/test/testdata/simple-resource-schema/pulumi_example/resource.py
vendored
Normal file
79
pkg/codegen/internal/test/testdata/simple-resource-schema/pulumi_example/resource.py
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import warnings
|
||||
import pulumi
|
||||
import pulumi.runtime
|
||||
from typing import Any, Mapping, Optional, Sequence, Union
|
||||
from . import _utilities, _tables
|
||||
|
||||
__all__ = ['Resource']
|
||||
|
||||
|
||||
class Resource(pulumi.CustomResource):
|
||||
def __init__(__self__,
|
||||
resource_name: str,
|
||||
opts: Optional[pulumi.ResourceOptions] = None,
|
||||
bar: Optional[pulumi.Input[str]] = None,
|
||||
__props__=None,
|
||||
__name__=None,
|
||||
__opts__=None):
|
||||
"""
|
||||
Create a Resource resource with the given unique name, props, and options.
|
||||
:param str resource_name: The name of the resource.
|
||||
:param pulumi.ResourceOptions opts: Options for the resource.
|
||||
"""
|
||||
if __name__ is not None:
|
||||
warnings.warn("explicit use of __name__ is deprecated", DeprecationWarning)
|
||||
resource_name = __name__
|
||||
if __opts__ is not None:
|
||||
warnings.warn("explicit use of __opts__ is deprecated, use 'opts' instead", DeprecationWarning)
|
||||
opts = __opts__
|
||||
if opts is None:
|
||||
opts = pulumi.ResourceOptions()
|
||||
if not isinstance(opts, pulumi.ResourceOptions):
|
||||
raise TypeError('Expected resource options to be a ResourceOptions instance')
|
||||
if opts.version is None:
|
||||
opts.version = _utilities.get_version()
|
||||
if opts.id is None:
|
||||
if __props__ is not None:
|
||||
raise TypeError('__props__ is only valid when passed in combination with a valid opts.id to get an existing resource')
|
||||
__props__ = dict()
|
||||
|
||||
__props__['bar'] = bar
|
||||
super(Resource, __self__).__init__(
|
||||
'example::Resource',
|
||||
resource_name,
|
||||
__props__,
|
||||
opts)
|
||||
|
||||
@staticmethod
|
||||
def get(resource_name: str,
|
||||
id: pulumi.Input[str],
|
||||
opts: Optional[pulumi.ResourceOptions] = None) -> 'Resource':
|
||||
"""
|
||||
Get an existing Resource resource's state with the given name, id, and optional extra
|
||||
properties used to qualify the lookup.
|
||||
|
||||
:param str resource_name: The unique name of the resulting resource.
|
||||
:param pulumi.Input[str] id: The unique provider ID of the resource to lookup.
|
||||
:param pulumi.ResourceOptions opts: Options for the resource.
|
||||
"""
|
||||
opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(id=id))
|
||||
|
||||
__props__ = dict()
|
||||
|
||||
return Resource(resource_name, opts=opts, __props__=__props__)
|
||||
|
||||
@property
|
||||
@pulumi.getter
|
||||
def bar(self) -> pulumi.Output[Optional[str]]:
|
||||
return pulumi.get(self, "bar")
|
||||
|
||||
def translate_output_property(self, prop):
|
||||
return _tables.CAMEL_TO_SNAKE_CASE_TABLE.get(prop) or prop
|
||||
|
||||
def translate_input_property(self, prop):
|
||||
return _tables.SNAKE_TO_CAMEL_CASE_TABLE.get(prop) or prop
|
||||
|
66
pkg/codegen/internal/test/testdata/simple-resource-schema/resource.ts
vendored
Normal file
66
pkg/codegen/internal/test/testdata/simple-resource-schema/resource.ts
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
// *** WARNING: this file was generated by test. ***
|
||||
// *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as utilities from "./utilities";
|
||||
|
||||
export class Resource extends pulumi.CustomResource {
|
||||
/**
|
||||
* Get an existing Resource resource's state with the given name, ID, and optional extra
|
||||
* properties used to qualify the lookup.
|
||||
*
|
||||
* @param name The _unique_ name of the resulting resource.
|
||||
* @param id The _unique_ provider ID of the resource to lookup.
|
||||
* @param opts Optional settings to control the behavior of the CustomResource.
|
||||
*/
|
||||
public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): Resource {
|
||||
return new Resource(name, undefined as any, { ...opts, id: id });
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public static readonly __pulumiType = 'example::Resource';
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an instance of Resource. This is designed to work even
|
||||
* when multiple copies of the Pulumi SDK have been loaded into the same process.
|
||||
*/
|
||||
public static isInstance(obj: any): obj is Resource {
|
||||
if (obj === undefined || obj === null) {
|
||||
return false;
|
||||
}
|
||||
return obj['__pulumiType'] === Resource.__pulumiType;
|
||||
}
|
||||
|
||||
public readonly bar!: pulumi.Output<string | undefined>;
|
||||
|
||||
/**
|
||||
* Create a Resource resource with the given unique name, arguments, and options.
|
||||
*
|
||||
* @param name The _unique_ name of the resource.
|
||||
* @param args The arguments to use to populate this resource's properties.
|
||||
* @param opts A bag of options that control this resource's behavior.
|
||||
*/
|
||||
constructor(name: string, args?: ResourceArgs, opts?: pulumi.CustomResourceOptions) {
|
||||
let inputs: pulumi.Inputs = {};
|
||||
if (!(opts && opts.id)) {
|
||||
inputs["bar"] = args ? args.bar : undefined;
|
||||
} else {
|
||||
inputs["bar"] = undefined /*out*/;
|
||||
}
|
||||
if (!opts) {
|
||||
opts = {}
|
||||
}
|
||||
|
||||
if (!opts.version) {
|
||||
opts.version = utilities.getVersion();
|
||||
}
|
||||
super(Resource.__pulumiType, name, inputs, opts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The set of arguments for constructing a Resource resource.
|
||||
*/
|
||||
export interface ResourceArgs {
|
||||
readonly bar?: pulumi.Input<string>;
|
||||
}
|
70
pkg/codegen/internal/test/testdata/simple-resource-schema/schema.json
vendored
Normal file
70
pkg/codegen/internal/test/testdata/simple-resource-schema/schema.json
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"version": "0.0.1",
|
||||
"name": "example",
|
||||
"types": {
|
||||
"example::Object": {
|
||||
"properties": {
|
||||
"foo": {
|
||||
"$ref": "#/resources/example::Resource"
|
||||
},
|
||||
"bar": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"example::Resource": {
|
||||
"properties": {
|
||||
"bar": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"inputProperties": {
|
||||
"bar": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"example::OtherResource": {
|
||||
"isComponent": true,
|
||||
"properties": {
|
||||
"foo": {
|
||||
"$ref": "#/resources/example::Resource"
|
||||
}
|
||||
},
|
||||
"inputProperties": {
|
||||
"foo": {
|
||||
"$ref": "#/resources/example::Resource"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"functions": {
|
||||
"example::argFunction": {
|
||||
"inputs": {
|
||||
"properties": {
|
||||
"arg1": {
|
||||
"$ref": "#/resources/example::Resource"
|
||||
}
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
"properties": {
|
||||
"result": {
|
||||
"$ref": "#/resources/example::Resource"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"csharp": {},
|
||||
"go": {},
|
||||
"nodejs": {},
|
||||
"python": {}
|
||||
}
|
||||
}
|
|
@ -96,30 +96,39 @@ func (mod *modContext) details(t *schema.ObjectType) *typeDetails {
|
|||
return details
|
||||
}
|
||||
|
||||
func (mod *modContext) tokenToType(tok string, input bool) string {
|
||||
// token := pkg : module : member
|
||||
// module := path/to/module
|
||||
|
||||
func (mod *modContext) tokenToModName(tok string) string {
|
||||
components := strings.Split(tok, ":")
|
||||
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
||||
|
||||
modName, name := mod.pkg.TokenToModule(tok), title(components[2])
|
||||
modName := mod.pkg.TokenToModule(tok)
|
||||
if override, ok := mod.modToPkg[modName]; ok {
|
||||
modName = override
|
||||
}
|
||||
|
||||
root := "outputs."
|
||||
if input {
|
||||
root = "inputs."
|
||||
}
|
||||
|
||||
if modName != "" {
|
||||
modName = strings.Replace(modName, "/", ".", -1) + "."
|
||||
}
|
||||
|
||||
return modName
|
||||
}
|
||||
|
||||
func (mod *modContext) tokenToType(tok string, input bool) string {
|
||||
modName, name := mod.tokenToModName(tok), tokenToName(tok)
|
||||
|
||||
root := "outputs."
|
||||
if input {
|
||||
root = "inputs."
|
||||
}
|
||||
|
||||
return root + modName + title(name)
|
||||
}
|
||||
|
||||
func (mod *modContext) tokenToResource(tok string) string {
|
||||
modName, name := mod.tokenToModName(tok), tokenToName(tok)
|
||||
|
||||
return modName + title(name)
|
||||
}
|
||||
|
||||
func tokenToName(tok string) string {
|
||||
components := strings.Split(tok, ":")
|
||||
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
||||
|
@ -146,6 +155,8 @@ func (mod *modContext) typeString(t schema.Type, input, wrapInput, optional bool
|
|||
typ = fmt.Sprintf("{[key: string]: %v}", mod.typeString(t.ElementType, input, wrapInput, false, constValue))
|
||||
case *schema.ObjectType:
|
||||
typ = mod.tokenToType(t.Token, input)
|
||||
case *schema.ResourceType:
|
||||
typ = mod.tokenToResource(t.Token)
|
||||
case *schema.TokenType:
|
||||
typ = tokenToName(t.Token)
|
||||
case *schema.UnionType:
|
||||
|
@ -335,7 +346,7 @@ func (mod *modContext) getDefaultValue(dv *schema.DefaultValue, t schema.Type) (
|
|||
func (mod *modContext) genAlias(w io.Writer, alias *schema.Alias) {
|
||||
fmt.Fprintf(w, "{ ")
|
||||
|
||||
parts := []string{}
|
||||
var parts []string
|
||||
if alias.Name != nil {
|
||||
parts = append(parts, fmt.Sprintf("name: \"%v\"", *alias.Name))
|
||||
}
|
||||
|
@ -364,17 +375,22 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
|
|||
// Write the TypeDoc/JSDoc for the resource class
|
||||
printComment(w, codegen.FilterExamples(r.Comment, "typescript"), r.DeprecationMessage, "")
|
||||
|
||||
baseType := "CustomResource"
|
||||
if r.IsProvider {
|
||||
baseType = "ProviderResource"
|
||||
var baseType, optionsType string
|
||||
switch {
|
||||
case r.IsComponent:
|
||||
baseType, optionsType = "ComponentResource", "ComponentResourceOptions"
|
||||
case r.IsProvider:
|
||||
baseType, optionsType = "ProviderResource", "ResourceOptions"
|
||||
default:
|
||||
baseType, optionsType = "CustomResource", "CustomResourceOptions"
|
||||
}
|
||||
|
||||
// Begin defining the class.
|
||||
fmt.Fprintf(w, "export class %s extends pulumi.%s {\n", name, baseType)
|
||||
|
||||
// Emit a static factory to read instances of this resource unless this is a provider resource.
|
||||
// Emit a static factory to read instances of this resource unless this is a provider resource or ComponentResource.
|
||||
stateType := name + "State"
|
||||
if !r.IsProvider {
|
||||
if !r.IsProvider && !r.IsComponent {
|
||||
fmt.Fprintf(w, " /**\n")
|
||||
fmt.Fprintf(w, " * Get an existing %s resource's state with the given name, ID, and optional extra\n", name)
|
||||
fmt.Fprintf(w, " * properties used to qualify the lookup.\n")
|
||||
|
@ -393,7 +409,8 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
|
|||
stateParam, stateRef = fmt.Sprintf("state?: %s, ", stateType), "<any>state, "
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, " public static get(name: string, id: pulumi.Input<pulumi.ID>, %sopts?: pulumi.CustomResourceOptions): %s {\n", stateParam, name)
|
||||
fmt.Fprintf(w, " public static get(name: string, id: pulumi.Input<pulumi.ID>, %sopts?: pulumi.%s): %s {\n",
|
||||
stateParam, optionsType, name)
|
||||
if r.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
|
||||
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, r.DeprecationMessage)
|
||||
}
|
||||
|
@ -470,12 +487,12 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
|
|||
argsFlags = "?"
|
||||
}
|
||||
argsType := name + "Args"
|
||||
trailingBrace, optionsType := "", "CustomResourceOptions"
|
||||
if r.IsProvider {
|
||||
trailingBrace, optionsType = " {", "ResourceOptions"
|
||||
}
|
||||
if r.StateInputs == nil {
|
||||
var trailingBrace string
|
||||
switch {
|
||||
case r.IsProvider, r.StateInputs == nil:
|
||||
trailingBrace = " {"
|
||||
default:
|
||||
trailingBrace = ""
|
||||
}
|
||||
|
||||
if r.DeprecationMessage != "" {
|
||||
|
@ -540,11 +557,12 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
|
|||
if r.DeprecationMessage != "" {
|
||||
fmt.Fprintf(w, " /** @deprecated %s */\n", r.DeprecationMessage)
|
||||
}
|
||||
|
||||
// Now write out a general purpose constructor implementation that can handle the public signature as well as the
|
||||
// signature to support construction via `.get`. And then emit the body preamble which will pluck out the
|
||||
// conditional state into sensible variables using dynamic type tests.
|
||||
fmt.Fprintf(w, " constructor(name: string, argsOrState?: %s | %s, opts?: pulumi.CustomResourceOptions) {\n",
|
||||
argsType, stateType)
|
||||
fmt.Fprintf(w, " constructor(name: string, argsOrState?: %s | %s, opts?: pulumi.%s) {\n",
|
||||
argsType, stateType, optionsType)
|
||||
}
|
||||
if r.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
|
||||
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, r.DeprecationMessage)
|
||||
|
@ -628,7 +646,12 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
|
|||
fmt.Fprintf(w, " opts = opts ? pulumi.mergeOptions(opts, secretOpts) : secretOpts;\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, " super(%s.__pulumiType, name, inputs, opts);\n", name)
|
||||
// If it's a ComponentResource, set the remote option.
|
||||
if r.IsComponent {
|
||||
fmt.Fprintf(w, " super(%s.__pulumiType, name, inputs, opts, true /*remote*/);\n", name)
|
||||
} else {
|
||||
fmt.Fprintf(w, " super(%s.__pulumiType, name, inputs, opts);\n", name)
|
||||
}
|
||||
|
||||
// Finish the class.
|
||||
fmt.Fprintf(w, " }\n")
|
||||
|
@ -779,15 +802,9 @@ func (mod *modContext) getTypeImports(t schema.Type, recurse bool, imports map[s
|
|||
return false
|
||||
}
|
||||
seen.Add(t)
|
||||
switch t := t.(type) {
|
||||
case *schema.ArrayType:
|
||||
return mod.getTypeImports(t.ElementType, recurse, imports, seen)
|
||||
case *schema.MapType:
|
||||
return mod.getTypeImports(t.ElementType, recurse, imports, seen)
|
||||
case *schema.ObjectType:
|
||||
return true
|
||||
case *schema.TokenType:
|
||||
modName, name, modPath := mod.pkg.TokenToModule(t.Token), tokenToName(t.Token), "./index"
|
||||
|
||||
resourceOrTokenImport := func(tok string) bool {
|
||||
modName, name, modPath := mod.pkg.TokenToModule(tok), tokenToName(tok), "./index"
|
||||
if override, ok := mod.modToPkg[modName]; ok {
|
||||
modName = override
|
||||
}
|
||||
|
@ -804,6 +821,22 @@ func (mod *modContext) getTypeImports(t schema.Type, recurse bool, imports map[s
|
|||
}
|
||||
imports[modPath].Add(name)
|
||||
return false
|
||||
}
|
||||
|
||||
switch t := t.(type) {
|
||||
case *schema.ArrayType:
|
||||
return mod.getTypeImports(t.ElementType, recurse, imports, seen)
|
||||
case *schema.MapType:
|
||||
return mod.getTypeImports(t.ElementType, recurse, imports, seen)
|
||||
case *schema.ObjectType:
|
||||
for _, p := range t.Properties {
|
||||
mod.getTypeImports(p.Type, recurse, imports, seen)
|
||||
}
|
||||
return true
|
||||
case *schema.ResourceType:
|
||||
return resourceOrTokenImport(t.Token)
|
||||
case *schema.TokenType:
|
||||
return resourceOrTokenImport(t.Token)
|
||||
case *schema.UnionType:
|
||||
needsTypes := false
|
||||
for _, e := range t.ElementTypes {
|
||||
|
@ -824,6 +857,9 @@ func (mod *modContext) getImports(member interface{}, imports map[string]codegen
|
|||
needsTypes = mod.getTypeImports(p.Type, true, imports, seen) || needsTypes
|
||||
}
|
||||
return needsTypes
|
||||
case *schema.ResourceType:
|
||||
mod.getTypeImports(member, true, imports, seen)
|
||||
return false
|
||||
case *schema.Resource:
|
||||
needsTypes := false
|
||||
for _, p := range member.Properties {
|
||||
|
|
71
pkg/codegen/nodejs/gen_test.go
Normal file
71
pkg/codegen/nodejs/gen_test.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
package nodejs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGeneratePackage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
schemaDir string
|
||||
expectedFiles []string
|
||||
wantErr bool
|
||||
validator func(files, expectedFiles map[string][]byte)
|
||||
}{
|
||||
{
|
||||
"Simple schema with local resource properties",
|
||||
"simple-resource-schema",
|
||||
[]string{
|
||||
"resource.ts",
|
||||
"otherResource.ts",
|
||||
"argFunction.ts",
|
||||
},
|
||||
false,
|
||||
func(files, expectedFiles map[string][]byte) {
|
||||
for name, file := range expectedFiles {
|
||||
assert.Contains(t, files, name)
|
||||
assert.Equal(t, file, files[name])
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
testDir := filepath.Join("..", "internal", "test", "testdata")
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Read in, decode, and import the schema.
|
||||
schemaBytes, err := ioutil.ReadFile(
|
||||
filepath.Join(testDir, tt.schemaDir, "schema.json"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedFiles := map[string][]byte{}
|
||||
for _, file := range tt.expectedFiles {
|
||||
fileBytes, err := ioutil.ReadFile(filepath.Join(testDir, tt.schemaDir, file))
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedFiles[file] = fileBytes
|
||||
}
|
||||
|
||||
var pkgSpec schema.PackageSpec
|
||||
err = json.Unmarshal(schemaBytes, &pkgSpec)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pkg, err := schema.ImportSpec(pkgSpec, nil)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ImportSpec() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
files, err := GeneratePackage("test", pkg, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tt.validator(files, expectedFiles)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -109,7 +109,8 @@ func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName
|
|||
// TODO[pulumi/pulumi#5145]: Delete this function once all providers have UsesIOClasses set to true in their schema.
|
||||
// GetLanguageTypeStringLegacy returns the legacy type strings.
|
||||
func (d DocLanguageHelper) GetLanguageTypeStringLegacy(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string {
|
||||
name := pyType(t)
|
||||
mod := modContext{} // This is a dummy context since pyType is a method and is only needed for resource refs.
|
||||
name := mod.pyType(t)
|
||||
|
||||
// The Python SDK generator will simply return "list" or "dict" for enumerables.
|
||||
// So we examine the underlying types to provide some more information on
|
||||
|
|
|
@ -57,12 +57,18 @@ func (ss stringSet) has(s string) bool {
|
|||
|
||||
type imports stringSet
|
||||
|
||||
func (imports imports) add(mod *modContext, tok string, input bool) {
|
||||
imports.addIf(mod, tok, input, nil /*predicate*/)
|
||||
func (imports imports) addType(mod *modContext, tok string, input bool) {
|
||||
imports.addTypeIf(mod, tok, input, nil /*predicate*/)
|
||||
}
|
||||
|
||||
func (imports imports) addIf(mod *modContext, tok string, input bool, predicate func(imp string) bool) {
|
||||
if imp := mod.importFromToken(tok, input); imp != "" && (predicate == nil || predicate(imp)) {
|
||||
func (imports imports) addTypeIf(mod *modContext, tok string, input bool, predicate func(imp string) bool) {
|
||||
if imp := mod.importTypeFromToken(tok, input); imp != "" && (predicate == nil || predicate(imp)) {
|
||||
stringSet(imports).add(imp)
|
||||
}
|
||||
}
|
||||
|
||||
func (imports imports) addResource(mod *modContext, tok string) {
|
||||
if imp := mod.importResourceFromToken(tok); imp != "" {
|
||||
stringSet(imports).add(imp)
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +161,25 @@ func (mod *modContext) tokenToType(tok string, input, functionType bool) string
|
|||
return fmt.Sprintf("'%s%s%s%s'", modName, prefix, name, suffix)
|
||||
}
|
||||
|
||||
func (mod *modContext) tokenToResource(tok string) string {
|
||||
// token := pkg : module : member
|
||||
// module := path/to/module
|
||||
|
||||
components := strings.Split(tok, ":")
|
||||
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
||||
|
||||
modName, name := mod.tokenToModule(tok), title(components[2])
|
||||
|
||||
if modName == mod.mod {
|
||||
modName = ""
|
||||
}
|
||||
if modName != "" {
|
||||
modName = "_" + strings.ReplaceAll(modName, "/", ".") + "."
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s", modName, name)
|
||||
}
|
||||
|
||||
func tokenToName(tok string) string {
|
||||
components := strings.Split(tok, ":")
|
||||
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
||||
|
@ -434,7 +459,7 @@ func (mod *modContext) genInit(exports []string) string {
|
|||
return w.String()
|
||||
}
|
||||
|
||||
func (mod *modContext) importFromToken(tok string, input bool) string {
|
||||
func (mod *modContext) importTypeFromToken(tok string, input bool) string {
|
||||
modName := mod.tokenToModule(tok)
|
||||
if modName == mod.mod {
|
||||
if input {
|
||||
|
@ -460,13 +485,30 @@ func (mod *modContext) importFromToken(tok string, input bool) string {
|
|||
return fmt.Sprintf("from %s import %[2]s as _%[2]s", relImport, components[0])
|
||||
}
|
||||
|
||||
// emitConfigVariables emits all config vaiables in the given module, returning the resulting file.
|
||||
func (mod *modContext) importResourceFromToken(tok string) string {
|
||||
modName := mod.tokenToResource(tok)
|
||||
|
||||
rel, err := filepath.Rel(mod.mod, "")
|
||||
contract.Assert(err == nil)
|
||||
relRoot := path.Dir(rel)
|
||||
relImport := relPathToRelImport(relRoot)
|
||||
|
||||
components := strings.Split(modName, "/")
|
||||
return fmt.Sprintf("from %s import %s", relImport, components[0])
|
||||
}
|
||||
|
||||
// emitConfigVariables emits all config variables in the given module, returning the resulting file.
|
||||
func (mod *modContext) genConfig(variables []*schema.Property) (string, error) {
|
||||
w := &bytes.Buffer{}
|
||||
|
||||
imports, seen := imports{}, codegen.Set{}
|
||||
visitObjectTypesFromProperties(variables, seen, func(t *schema.ObjectType) {
|
||||
imports.add(mod, t.Token, false /*input*/)
|
||||
visitObjectTypesFromProperties(variables, seen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addType(mod, T.Token, false /*input*/)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
|
||||
mod.genHeader(w, true /*needsSDK*/, imports)
|
||||
|
@ -510,16 +552,26 @@ func (mod *modContext) genTypes(dir string, fs fs) error {
|
|||
imports, inputSeen, outputSeen := imports{}, codegen.Set{}, codegen.Set{}
|
||||
for _, t := range mod.types {
|
||||
if input && mod.details(t).inputType {
|
||||
visitObjectTypesFromProperties(t.Properties, inputSeen, func(t *schema.ObjectType) {
|
||||
imports.addIf(mod, t.Token, true /*input*/, func(imp string) bool {
|
||||
// No need to import `._inputs` inside _inputs.py.
|
||||
return imp != "from ._inputs import *"
|
||||
})
|
||||
visitObjectTypesFromProperties(t.Properties, inputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addTypeIf(mod, T.Token, true /*input*/, func(imp string) bool {
|
||||
// No need to import `._inputs` inside _inputs.py.
|
||||
return imp != "from ._inputs import *"
|
||||
})
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
if !input && mod.details(t).outputType {
|
||||
visitObjectTypesFromProperties(t.Properties, outputSeen, func(t *schema.ObjectType) {
|
||||
imports.add(mod, t.Token, false /*input*/)
|
||||
visitObjectTypesFromProperties(t.Properties, outputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addType(mod, T.Token, false /*input*/)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -594,7 +646,7 @@ func (mod *modContext) genAwaitableType(w io.Writer, obj *schema.ObjectType) str
|
|||
for _, prop := range obj.Properties {
|
||||
// Check that required arguments are present. Also check that types are as expected.
|
||||
pname := PyName(prop.Name)
|
||||
ptype := pyType(prop.Type)
|
||||
ptype := mod.pyType(prop.Type)
|
||||
fmt.Fprintf(w, " if %s and not isinstance(%s, %s):\n", pname, pname, ptype)
|
||||
fmt.Fprintf(w, " raise TypeError(\"Expected argument '%s' to be a %s\")\n", pname, ptype)
|
||||
|
||||
|
@ -648,15 +700,30 @@ func (mod *modContext) genResource(res *schema.Resource) (string, error) {
|
|||
w := &bytes.Buffer{}
|
||||
|
||||
imports, inputSeen, outputSeen := imports{}, codegen.Set{}, codegen.Set{}
|
||||
visitObjectTypesFromProperties(res.Properties, outputSeen, func(t *schema.ObjectType) {
|
||||
imports.add(mod, t.Token, false /*input*/)
|
||||
visitObjectTypesFromProperties(res.Properties, outputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addType(mod, T.Token, false /*input*/)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
visitObjectTypesFromProperties(res.InputProperties, inputSeen, func(t *schema.ObjectType) {
|
||||
imports.add(mod, t.Token, !res.IsProvider)
|
||||
visitObjectTypesFromProperties(res.InputProperties, inputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addType(mod, T.Token, !res.IsProvider)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
if res.StateInputs != nil {
|
||||
visitObjectTypesFromProperties(res.StateInputs.Properties, inputSeen, func(t *schema.ObjectType) {
|
||||
imports.add(mod, t.Token, true /*input*/)
|
||||
visitObjectTypesFromProperties(res.StateInputs.Properties, inputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addType(mod, T.Token, true /*input*/)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -670,9 +737,14 @@ func (mod *modContext) genResource(res *schema.Resource) (string, error) {
|
|||
// Export only the symbols we want exported.
|
||||
fmt.Fprintf(w, "__all__ = ['%s']\n\n", name)
|
||||
|
||||
baseType := "pulumi.CustomResource"
|
||||
if res.IsProvider {
|
||||
var baseType string
|
||||
switch {
|
||||
case res.IsProvider:
|
||||
baseType = "pulumi.ProviderResource"
|
||||
case res.IsComponent:
|
||||
baseType = "pulumi.ComponentResource"
|
||||
default:
|
||||
baseType = "pulumi.CustomResource"
|
||||
}
|
||||
|
||||
if !res.IsProvider && res.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
|
||||
|
@ -719,7 +791,13 @@ func (mod *modContext) genResource(res *schema.Resource) (string, error) {
|
|||
fmt.Fprintf(w, " raise TypeError('Expected resource options to be a ResourceOptions instance')\n")
|
||||
fmt.Fprintf(w, " if opts.version is None:\n")
|
||||
fmt.Fprintf(w, " opts.version = _utilities.get_version()\n")
|
||||
fmt.Fprintf(w, " if opts.id is None:\n")
|
||||
if res.IsComponent {
|
||||
fmt.Fprintf(w, " if opts.id is not None:\n")
|
||||
fmt.Fprintf(w, " raise ValueError('ComponentResource classes do not support opts.id')\n")
|
||||
fmt.Fprintf(w, " else:\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, " if opts.id is None:\n")
|
||||
}
|
||||
fmt.Fprintf(w, " if __props__ is not None:\n")
|
||||
fmt.Fprintf(w, " raise TypeError(")
|
||||
fmt.Fprintf(w, "'__props__ is only valid when passed in combination with a valid opts.id to get an existing resource')\n")
|
||||
|
@ -827,10 +905,15 @@ func (mod *modContext) genResource(res *schema.Resource) (string, error) {
|
|||
fmt.Fprintf(w, " '%s',\n", tok)
|
||||
fmt.Fprintf(w, " resource_name,\n")
|
||||
fmt.Fprintf(w, " __props__,\n")
|
||||
fmt.Fprintf(w, " opts)\n")
|
||||
if res.IsComponent {
|
||||
fmt.Fprintf(w, " opts,\n")
|
||||
fmt.Fprintf(w, " remote=True)\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, " opts)\n")
|
||||
}
|
||||
fmt.Fprintf(w, "\n")
|
||||
|
||||
if !res.IsProvider {
|
||||
if !res.IsProvider && !res.IsComponent {
|
||||
fmt.Fprintf(w, " @staticmethod\n")
|
||||
fmt.Fprintf(w, " def get(resource_name: str,\n")
|
||||
fmt.Fprintf(w, " id: pulumi.Input[str],\n")
|
||||
|
@ -947,13 +1030,23 @@ func (mod *modContext) genFunction(fun *schema.Function) (string, error) {
|
|||
|
||||
imports, inputSeen, outputSeen := imports{}, codegen.Set{}, codegen.Set{}
|
||||
if fun.Inputs != nil {
|
||||
visitObjectTypesFromProperties(fun.Inputs.Properties, inputSeen, func(t *schema.ObjectType) {
|
||||
imports.add(mod, t.Token, true /*input*/)
|
||||
visitObjectTypesFromProperties(fun.Inputs.Properties, inputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addType(mod, T.Token, true /*input*/)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
if fun.Outputs != nil {
|
||||
visitObjectTypesFromProperties(fun.Outputs.Properties, outputSeen, func(t *schema.ObjectType) {
|
||||
imports.add(mod, t.Token, false /*input*/)
|
||||
visitObjectTypesFromProperties(fun.Outputs.Properties, outputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
imports.addType(mod, T.Token, false /*input*/)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1072,13 +1165,13 @@ func (mod *modContext) genFunction(fun *schema.Function) (string, error) {
|
|||
return w.String(), nil
|
||||
}
|
||||
|
||||
func visitObjectTypesFromProperties(properties []*schema.Property, seen codegen.Set, visitor func(*schema.ObjectType)) {
|
||||
func visitObjectTypesFromProperties(properties []*schema.Property, seen codegen.Set, visitor func(objectOrResource interface{})) {
|
||||
for _, p := range properties {
|
||||
visitObjectTypes(p.Type, seen, visitor)
|
||||
}
|
||||
}
|
||||
|
||||
func visitObjectTypes(t schema.Type, seen codegen.Set, visitor func(*schema.ObjectType)) {
|
||||
func visitObjectTypes(t schema.Type, seen codegen.Set, visitor func(objectOrResource interface{})) {
|
||||
if seen.Has(t) {
|
||||
return
|
||||
}
|
||||
|
@ -1093,6 +1186,8 @@ func visitObjectTypes(t schema.Type, seen codegen.Set, visitor func(*schema.Obje
|
|||
visitObjectTypes(p.Type, seen, visitor)
|
||||
}
|
||||
visitor(t)
|
||||
case *schema.ResourceType:
|
||||
visitor(t)
|
||||
case *schema.UnionType:
|
||||
for _, e := range t.ElementTypes {
|
||||
visitObjectTypes(e, seen, visitor)
|
||||
|
@ -1478,6 +1573,8 @@ func (mod *modContext) typeString(t schema.Type, input, wrapInput, optional, acc
|
|||
if acceptMapping {
|
||||
typ = fmt.Sprintf("pulumi.InputType[%s]", typ)
|
||||
}
|
||||
case *schema.ResourceType:
|
||||
typ = fmt.Sprintf("'%s'", mod.tokenToResource(t.Token))
|
||||
case *schema.TokenType:
|
||||
// Use the underlying type for now.
|
||||
if t.UnderlyingType != nil {
|
||||
|
@ -1549,15 +1646,17 @@ func (mod *modContext) typeString(t schema.Type, input, wrapInput, optional, acc
|
|||
|
||||
// pyType returns the expected runtime type for the given variable. Of course, being a dynamic language, this
|
||||
// check is not exhaustive, but it should be good enough to catch 80% of the cases early on.
|
||||
func pyType(typ schema.Type) string {
|
||||
func (mod *modContext) pyType(typ schema.Type) string {
|
||||
switch typ := typ.(type) {
|
||||
case *schema.ArrayType:
|
||||
return "list"
|
||||
case *schema.MapType, *schema.ObjectType, *schema.UnionType:
|
||||
return "dict"
|
||||
case *schema.ResourceType:
|
||||
return mod.tokenToResource(typ.Token)
|
||||
case *schema.TokenType:
|
||||
if typ.UnderlyingType != nil {
|
||||
return pyType(typ.UnderlyingType)
|
||||
return mod.pyType(typ.UnderlyingType)
|
||||
}
|
||||
return "dict"
|
||||
default:
|
||||
|
@ -1845,26 +1944,40 @@ func generateModuleContextMap(tool string, pkg *schema.Package, info PackageInfo
|
|||
}
|
||||
|
||||
inputSeen, outputSeen := codegen.Set{}, codegen.Set{}
|
||||
visitObjectTypesFromProperties(pkg.Config, outputSeen, func(t *schema.ObjectType) {
|
||||
getModFromToken(t.Token).details(t).outputType = true
|
||||
visitObjectTypesFromProperties(pkg.Config, outputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
getModFromToken(T.Token).details(T).outputType = true
|
||||
}
|
||||
})
|
||||
|
||||
// Find input and output types referenced by resources.
|
||||
scanResource := func(r *schema.Resource) {
|
||||
mod := getModFromToken(r.Token)
|
||||
mod.resources = append(mod.resources, r)
|
||||
visitObjectTypesFromProperties(r.Properties, outputSeen, func(t *schema.ObjectType) {
|
||||
getModFromToken(t.Token).details(t).outputType = true
|
||||
})
|
||||
visitObjectTypesFromProperties(r.InputProperties, inputSeen, func(t *schema.ObjectType) {
|
||||
if r.IsProvider {
|
||||
getModFromToken(t.Token).details(t).outputType = true
|
||||
visitObjectTypesFromProperties(r.Properties, outputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
getModFromToken(T.Token).details(T).outputType = true
|
||||
}
|
||||
})
|
||||
visitObjectTypesFromProperties(r.InputProperties, inputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
if r.IsProvider {
|
||||
getModFromToken(T.Token).details(T).outputType = true
|
||||
}
|
||||
getModFromToken(T.Token).details(T).inputType = true
|
||||
}
|
||||
getModFromToken(t.Token).details(t).inputType = true
|
||||
})
|
||||
if r.StateInputs != nil {
|
||||
visitObjectTypes(r.StateInputs, inputSeen, func(t *schema.ObjectType) {
|
||||
getModFromToken(t.Token).details(t).inputType = true
|
||||
visitObjectTypes(r.StateInputs, inputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
getModFromToken(T.Token).details(T).inputType = true
|
||||
case *schema.ResourceType:
|
||||
getModFromToken(T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1879,15 +1992,25 @@ func generateModuleContextMap(tool string, pkg *schema.Package, info PackageInfo
|
|||
mod := getModFromToken(f.Token)
|
||||
mod.functions = append(mod.functions, f)
|
||||
if f.Inputs != nil {
|
||||
visitObjectTypes(f.Inputs, inputSeen, func(t *schema.ObjectType) {
|
||||
getModFromToken(t.Token).details(t).inputType = true
|
||||
getModFromToken(t.Token).details(t).functionType = true
|
||||
visitObjectTypes(f.Inputs, inputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
getModFromToken(T.Token).details(T).inputType = true
|
||||
getModFromToken(T.Token).details(T).functionType = true
|
||||
case *schema.ResourceType:
|
||||
getModFromToken(T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
if f.Outputs != nil {
|
||||
visitObjectTypes(f.Outputs, outputSeen, func(t *schema.ObjectType) {
|
||||
getModFromToken(t.Token).details(t).outputType = true
|
||||
getModFromToken(t.Token).details(t).functionType = true
|
||||
visitObjectTypes(f.Outputs, outputSeen, func(t interface{}) {
|
||||
switch T := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
getModFromToken(T.Token).details(T).outputType = true
|
||||
getModFromToken(T.Token).details(T).functionType = true
|
||||
case *schema.ResourceType:
|
||||
getModFromToken(T.Token)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
package python
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var pathTests = []struct {
|
||||
input string
|
||||
|
@ -26,3 +34,64 @@ func TestRelPathToRelImport(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratePackage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
schemaDir string
|
||||
expectedFiles []string
|
||||
wantErr bool
|
||||
validator func(files, expectedFiles map[string][]byte)
|
||||
}{
|
||||
{
|
||||
"Simple schema with local resource properties",
|
||||
"simple-resource-schema",
|
||||
[]string{
|
||||
filepath.Join("pulumi_example", "resource.py"),
|
||||
filepath.Join("pulumi_example", "other_resource.py"),
|
||||
filepath.Join("pulumi_example", "arg_function.py"),
|
||||
},
|
||||
false,
|
||||
func(files, expectedFiles map[string][]byte) {
|
||||
for name, file := range expectedFiles {
|
||||
assert.Contains(t, files, name)
|
||||
assert.Equal(t, file, files[name])
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testDir := filepath.Join("..", "internal", "test", "testdata")
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Read in, decode, and import the schema.
|
||||
schemaBytes, err := ioutil.ReadFile(filepath.Join(testDir, tt.schemaDir, "schema.json"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedFiles := map[string][]byte{}
|
||||
for _, file := range tt.expectedFiles {
|
||||
fileBytes, err := ioutil.ReadFile(filepath.Join(testDir, tt.schemaDir, file))
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedFiles[file] = fileBytes
|
||||
}
|
||||
|
||||
var pkgSpec schema.PackageSpec
|
||||
err = json.Unmarshal(schemaBytes, &pkgSpec)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pkg, err := schema.ImportSpec(pkgSpec, nil)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ImportSpec() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
files, err := GeneratePackage("test", pkg, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tt.validator(files, expectedFiles)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import (
|
|||
|
||||
// TODO:
|
||||
// - Providerless packages
|
||||
// - Adjustments to accommodate docs + cross-lang packages (e.g references to resources from POD types)
|
||||
|
||||
// Type represents a datatype in the Pulumi Schema. Types created by this package are identical if they are
|
||||
// equal values.
|
||||
|
@ -215,6 +214,17 @@ func (t *ObjectType) String() string {
|
|||
|
||||
func (*ObjectType) isType() {}
|
||||
|
||||
type ResourceType struct {
|
||||
// Token is the type's Pulumi type token.
|
||||
Token string
|
||||
}
|
||||
|
||||
func (t *ResourceType) String() string {
|
||||
return t.Token
|
||||
}
|
||||
|
||||
func (t *ResourceType) isType() {}
|
||||
|
||||
// TokenType represents an opaque type that is referred to only by its token. A TokenType may have an underlying type
|
||||
// that can be used in place of the token.
|
||||
type TokenType struct {
|
||||
|
@ -295,6 +305,8 @@ type Resource struct {
|
|||
DeprecationMessage string
|
||||
// Language specifies additional language-specific data about the resource.
|
||||
Language map[string]interface{}
|
||||
// IsComponent indicates whether the resource is a ComponentResource.
|
||||
IsComponent bool
|
||||
}
|
||||
|
||||
// Function describes a Pulumi function.
|
||||
|
@ -596,6 +608,7 @@ type TypeSpec struct {
|
|||
// Ref is a reference to a type in this or another document. For example, the built-in Archive, Asset, and Any
|
||||
// types are referenced as "pulumi.json#/Archive", "pulumi.json#/Asset", and "pulumi.json#/Any", respectively.
|
||||
// A type from this document is referenced as "#/types/pulumi:type:token".
|
||||
// A resource from this document is referenced as "#/resources/pulumi:type:token".
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
// AdditionalProperties, if set, describes the element type of an "object" (i.e. a string -> value map).
|
||||
AdditionalProperties *TypeSpec `json:"additionalProperties,omitempty"`
|
||||
|
@ -695,6 +708,8 @@ type ResourceSpec struct {
|
|||
DeprecationMessage string `json:"deprecationMessage,omitempty"`
|
||||
// Language specifies additional language-specific data about the resource.
|
||||
Language map[string]json.RawMessage `json:"language,omitempty"`
|
||||
// IsComponent indicates whether the resource is a ComponentResource.
|
||||
IsComponent bool `json:"isComponent,omitempty"`
|
||||
}
|
||||
|
||||
// FunctionSpec is the serializable form of a function description.
|
||||
|
@ -820,6 +835,9 @@ func ImportSpec(spec PackageSpec, languages map[string]Language) (*Package, erro
|
|||
|
||||
// Build the type list.
|
||||
var typeList []Type
|
||||
for _, t := range types.resources {
|
||||
typeList = append(typeList, t)
|
||||
}
|
||||
for _, t := range types.objects {
|
||||
typeList = append(typeList, t)
|
||||
}
|
||||
|
@ -874,15 +892,18 @@ func ImportSpec(spec PackageSpec, languages map[string]Language) (*Package, erro
|
|||
return pkg, nil
|
||||
}
|
||||
|
||||
// types facilitates interning (only storing a single reference to an object) during schema processing. The fields
|
||||
// correspond to fields in the schema, and are populated during the binding process.
|
||||
type types struct {
|
||||
pkg *Package
|
||||
|
||||
objects map[string]*ObjectType
|
||||
arrays map[Type]*ArrayType
|
||||
maps map[Type]*MapType
|
||||
unions map[string]*UnionType
|
||||
tokens map[string]*TokenType
|
||||
enums map[string]*EnumType
|
||||
resources map[string]*ResourceType
|
||||
objects map[string]*ObjectType
|
||||
arrays map[Type]*ArrayType
|
||||
maps map[Type]*MapType
|
||||
unions map[string]*UnionType
|
||||
tokens map[string]*TokenType
|
||||
enums map[string]*EnumType
|
||||
}
|
||||
|
||||
func (t *types) bindPrimitiveType(name string) (Type, error) {
|
||||
|
@ -914,33 +935,47 @@ func (t *types) bindType(spec TypeSpec) (Type, error) {
|
|||
}
|
||||
|
||||
// Parse the ref and look up the type in the type map.
|
||||
if !strings.HasPrefix(spec.Ref, "#/types/") {
|
||||
return nil, errors.Errorf("failed to parse ref %s", spec.Ref)
|
||||
}
|
||||
|
||||
token, err := url.PathUnescape(spec.Ref[len("#/types/"):])
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to parse ref %s", spec.Ref)
|
||||
}
|
||||
if typ, ok := t.objects[token]; ok {
|
||||
return typ, nil
|
||||
}
|
||||
if typ, ok := t.enums[token]; ok {
|
||||
return typ, nil
|
||||
}
|
||||
typ, ok := t.tokens[token]
|
||||
if !ok {
|
||||
typ = &TokenType{Token: token}
|
||||
if spec.Type != "" {
|
||||
ut, err := t.bindType(TypeSpec{Type: spec.Type})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typ.UnderlyingType = ut
|
||||
switch {
|
||||
case strings.HasPrefix(spec.Ref, "#/types/"):
|
||||
token, err := url.PathUnescape(spec.Ref[len("#/types/"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.tokens[token] = typ
|
||||
|
||||
if typ, ok := t.objects[token]; ok {
|
||||
return typ, nil
|
||||
}
|
||||
if typ, ok := t.enums[token]; ok {
|
||||
return typ, nil
|
||||
}
|
||||
typ, ok := t.tokens[token]
|
||||
if !ok {
|
||||
typ = &TokenType{Token: token}
|
||||
if spec.Type != "" {
|
||||
ut, err := t.bindType(TypeSpec{Type: spec.Type})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typ.UnderlyingType = ut
|
||||
}
|
||||
t.tokens[token] = typ
|
||||
}
|
||||
return typ, nil
|
||||
case strings.HasPrefix(spec.Ref, "#/resources/"):
|
||||
token, err := url.PathUnescape(spec.Ref[len("#/resources/"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
typ, ok := t.resources[token]
|
||||
if !ok {
|
||||
typ = &ResourceType{Token: token}
|
||||
t.resources[token] = typ
|
||||
}
|
||||
return typ, nil
|
||||
default:
|
||||
return nil, errors.Errorf("failed to parse ref %s", spec.Ref)
|
||||
}
|
||||
return typ, nil
|
||||
}
|
||||
|
||||
if spec.OneOf != nil {
|
||||
|
@ -1184,6 +1219,19 @@ func (t *types) bindObjectType(token string, spec ObjectTypeSpec) (*ObjectType,
|
|||
return obj, nil
|
||||
}
|
||||
|
||||
func (t *types) bindResourceTypeDetails(obj *ResourceType, token string) error {
|
||||
obj.Token = token
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *types) bindResourceType(token string) (*ResourceType, error) {
|
||||
r := &ResourceType{}
|
||||
if err := t.bindResourceTypeDetails(r, token); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (t *types) bindEnumTypeDetails(enum *EnumType, token string, spec ComplexTypeSpec) error {
|
||||
typ, err := t.bindType(TypeSpec{Type: spec.Type})
|
||||
if err != nil {
|
||||
|
@ -1255,13 +1303,14 @@ func (t *types) bindEnumType(token string, spec ComplexTypeSpec) (*EnumType, err
|
|||
|
||||
func bindTypes(pkg *Package, complexTypes map[string]ComplexTypeSpec) (*types, error) {
|
||||
typs := &types{
|
||||
pkg: pkg,
|
||||
objects: map[string]*ObjectType{},
|
||||
arrays: map[Type]*ArrayType{},
|
||||
maps: map[Type]*MapType{},
|
||||
unions: map[string]*UnionType{},
|
||||
tokens: map[string]*TokenType{},
|
||||
enums: map[string]*EnumType{},
|
||||
pkg: pkg,
|
||||
resources: map[string]*ResourceType{},
|
||||
objects: map[string]*ObjectType{},
|
||||
arrays: map[Type]*ArrayType{},
|
||||
maps: map[Type]*MapType{},
|
||||
unions: map[string]*UnionType{},
|
||||
tokens: map[string]*TokenType{},
|
||||
enums: map[string]*EnumType{},
|
||||
}
|
||||
|
||||
// Declare object and enum types before processing properties.
|
||||
|
@ -1277,6 +1326,11 @@ func bindTypes(pkg *Package, complexTypes map[string]ComplexTypeSpec) (*types, e
|
|||
}
|
||||
}
|
||||
|
||||
// Process resources.
|
||||
for _, r := range pkg.Resources {
|
||||
typs.resources[r.Token] = &ResourceType{Token: r.Token}
|
||||
}
|
||||
|
||||
// Process properties.
|
||||
for token, spec := range complexTypes {
|
||||
if spec.Type == "object" {
|
||||
|
@ -1338,6 +1392,7 @@ func bindResource(token string, spec ResourceSpec, types *types) (*Resource, err
|
|||
Aliases: aliases,
|
||||
DeprecationMessage: spec.DeprecationMessage,
|
||||
Language: language,
|
||||
IsComponent: spec.IsComponent,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -119,3 +119,48 @@ func TestEnums(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportResourceRef(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
schemaFile string
|
||||
wantErr bool
|
||||
validator func(pkg *Package)
|
||||
}{
|
||||
{
|
||||
"valid",
|
||||
"simple-resource-schema/schema.json",
|
||||
false,
|
||||
func(pkg *Package) {
|
||||
for _, r := range pkg.Resources {
|
||||
if r.Token == "example::OtherResource" {
|
||||
for _, p := range r.Properties {
|
||||
if p.Name == "foo" {
|
||||
assert.IsType(t, &ResourceType{}, p.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Read in, decode, and import the schema.
|
||||
schemaBytes, err := ioutil.ReadFile(
|
||||
filepath.Join("..", "internal", "test", "testdata", tt.schemaFile))
|
||||
assert.NoError(t, err)
|
||||
|
||||
var pkgSpec PackageSpec
|
||||
err = json.Unmarshal(schemaBytes, &pkgSpec)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pkg, err := ImportSpec(pkgSpec, nil)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ImportSpec() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
tt.validator(pkg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
52
scripts/publish_npm.sh
Executable file
52
scripts/publish_npm.sh
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/bash
|
||||
# publish_npm.sh uploads our packages to npm
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
readonly ROOT=$(dirname "${0}")/..
|
||||
|
||||
if [[ "${TRAVIS_PUBLISH_PACKAGES:-}" == "true" ]]; then
|
||||
echo "Publishing NPM package to NPMjs.com:"
|
||||
NPM_TAG="dev"
|
||||
|
||||
if [[ "${TRAVIS_BRANCH:-}" == features/* ]]; then
|
||||
NPM_TAG=$(echo "${TRAVIS_BRANCH}" | sed -e 's|^features/|feature-|g')
|
||||
fi
|
||||
|
||||
if [[ "${TRAVIS_BRANCH:-}" == feature-* ]]; then
|
||||
NPM_TAG=$(echo "${TRAVIS_BRANCH}")
|
||||
fi
|
||||
|
||||
PKG_NAME=$(jq -r .name < "${ROOT}/sdk/nodejs/bin/package.json")
|
||||
PKG_VERSION=$(jq -r .version < "${ROOT}/sdk/nodejs/bin/package.json")
|
||||
|
||||
# If the package doesn't have an alpha tag, use the tag of latest instead of
|
||||
# dev. NPM uses this tag as the default version to add, so we want it to mean
|
||||
# the newest released version.
|
||||
if [[ "${PKG_VERSION}" != *-alpha* ]]; then
|
||||
NPM_TAG="latest"
|
||||
fi
|
||||
|
||||
# Now, perform the publish. The logic here is a little goofy because npm provides
|
||||
# no way to say "if the package already exists, don't fail" but we want these
|
||||
# semantics (so, for example, we can restart builds which may have failed after
|
||||
# publishing, or so two builds can run concurrently, which is the case for when we
|
||||
# tag master right after pushing a new commit and the push and tag travis jobs both
|
||||
# get the same version.
|
||||
#
|
||||
# We exploit the fact that `npm info <package-name>@<package-version>` has no output
|
||||
# when the package does not exist.
|
||||
pushd "${ROOT}/sdk/nodejs/bin"
|
||||
if [ "$(npm info ${PKG_NAME}@${PKG_VERSION})" == "" ]; then
|
||||
if ! npm publish -tag "${NPM_TAG}"; then
|
||||
# if we get here, we have a TOCTOU issue, so check again
|
||||
# to see if it published. If it didn't bail out.
|
||||
if [ "$(npm info ${PKG_NAME}@${PKG_VERSION})" == "" ]; then
|
||||
echo "NPM publishing failed, aborting"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
npm info 2>/dev/null
|
||||
popd
|
||||
fi
|
|
@ -61,3 +61,9 @@ dist::
|
|||
|
||||
brew:: dist
|
||||
go install -ldflags "-X github.com/pulumi/pulumi/sdk/v2/go/common/version.Version=${VERSION}" ${LANGHOST_PKG}
|
||||
|
||||
publish:: build install
|
||||
echo "Publishing .nupkgs to nuget.org:"
|
||||
find /opt/pulumi/nuget -name 'Pulumi*.nupkg' \
|
||||
-exec dotnet nuget push -k ${NUGET_PUBLISH_KEY} -s https://api.nuget.org/v3/index.json {} ';'
|
||||
|
||||
|
|
|
@ -22,11 +22,12 @@ namespace Pulumi.Tests.Serialization
|
|||
public readonly double D;
|
||||
public readonly ImmutableArray<bool> Array;
|
||||
public readonly ImmutableDictionary<string, int> Dict;
|
||||
public readonly object Obj;
|
||||
|
||||
[OutputConstructor]
|
||||
public ComplexType1(
|
||||
string s, bool b, int i, double d,
|
||||
ImmutableArray<bool> array, ImmutableDictionary<string, int> dict)
|
||||
ImmutableArray<bool> array, ImmutableDictionary<string, int> dict, object obj)
|
||||
{
|
||||
S = s;
|
||||
B = b;
|
||||
|
@ -34,6 +35,7 @@ namespace Pulumi.Tests.Serialization
|
|||
D = d;
|
||||
Array = array;
|
||||
Dict = dict;
|
||||
Obj = obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +50,7 @@ namespace Pulumi.Tests.Serialization
|
|||
{ "d", 1.5 },
|
||||
{ "array", new List<object> { true, false } },
|
||||
{ "dict", new Dictionary<object, object> { { "k", 10 } } },
|
||||
{ "obj", "test" }
|
||||
}));
|
||||
|
||||
Assert.Equal("str", data.Value.S);
|
||||
|
@ -56,6 +59,7 @@ namespace Pulumi.Tests.Serialization
|
|||
Assert.Equal(1.5, data.Value.D);
|
||||
AssertEx.SequenceEqual(ImmutableArray<bool>.Empty.Add(true).Add(false), data.Value.Array);
|
||||
AssertEx.MapEqual(ImmutableDictionary<string, int>.Empty.Add("k", 10), data.Value.Dict);
|
||||
Assert.Equal("test", data.Value.Obj);
|
||||
|
||||
Assert.True(data.IsKnown);
|
||||
}
|
||||
|
@ -98,6 +102,7 @@ namespace Pulumi.Tests.Serialization
|
|||
{ "d", 1.1 },
|
||||
{ "array", new List<object> { false, false } },
|
||||
{ "dict", new Dictionary<object, object> { { "k", 1 } } },
|
||||
{ "obj", 50.0 },
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -112,6 +117,7 @@ namespace Pulumi.Tests.Serialization
|
|||
{ "d", 2.2 },
|
||||
{ "array", new List<object> { false, true } },
|
||||
{ "dict", new Dictionary<object, object> { { "k", 2 } } },
|
||||
{ "obj", true },
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -129,6 +135,7 @@ namespace Pulumi.Tests.Serialization
|
|||
{ "d", 3.3 },
|
||||
{ "array", new List<object> { true, false } },
|
||||
{ "dict", new Dictionary<object, object> { { "k", 3 } } },
|
||||
{ "obj", new Dictionary<object, object> { { "o", 5.5 } } },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +149,7 @@ namespace Pulumi.Tests.Serialization
|
|||
Assert.Equal(1.1, value.D);
|
||||
AssertEx.SequenceEqual(ImmutableArray<bool>.Empty.Add(false).Add(false), value.Array);
|
||||
AssertEx.MapEqual(ImmutableDictionary<string, int>.Empty.Add("k", 1), value.Dict);
|
||||
Assert.Equal(50.0, value.Obj);
|
||||
|
||||
Assert.Single(data.C2Array);
|
||||
value = data.C2Array[0];
|
||||
|
@ -151,6 +159,7 @@ namespace Pulumi.Tests.Serialization
|
|||
Assert.Equal(2.2, value.D);
|
||||
AssertEx.SequenceEqual(ImmutableArray<bool>.Empty.Add(false).Add(true), value.Array);
|
||||
AssertEx.MapEqual(ImmutableDictionary<string, int>.Empty.Add("k", 2), value.Dict);
|
||||
Assert.Equal(true, value.Obj);
|
||||
|
||||
Assert.Single(data.C2Map);
|
||||
var (key, val) = data.C2Map.Single();
|
||||
|
@ -163,6 +172,7 @@ namespace Pulumi.Tests.Serialization
|
|||
Assert.Equal(3.3, value.D);
|
||||
AssertEx.SequenceEqual(ImmutableArray<bool>.Empty.Add(true).Add(false), value.Array);
|
||||
AssertEx.MapEqual(ImmutableDictionary<string, int>.Empty.Add("k", 3), value.Dict);
|
||||
AssertEx.MapEqual(ImmutableDictionary<string, object>.Empty.Add("o", 5.5), (IDictionary<string, object>)value.Obj);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -86,6 +86,9 @@ namespace Pulumi.Serialization
|
|||
return ((int)d, exception);
|
||||
}
|
||||
|
||||
if (targetType == typeof(object))
|
||||
return (val, null);
|
||||
|
||||
if (targetType == typeof(Asset))
|
||||
return TryEnsureType<Asset>(context, val);
|
||||
|
||||
|
@ -310,6 +313,7 @@ namespace Pulumi.Serialization
|
|||
targetType == typeof(int) ||
|
||||
targetType == typeof(double) ||
|
||||
targetType == typeof(string) ||
|
||||
targetType == typeof(object) ||
|
||||
targetType == typeof(Asset) ||
|
||||
targetType == typeof(Archive) ||
|
||||
targetType == typeof(AssetOrArchive) ||
|
||||
|
|
|
@ -17,7 +17,6 @@ package gitutil
|
|||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
@ -80,7 +79,7 @@ func GetGitRepository(dir string) (*git.Repository, error) {
|
|||
}
|
||||
|
||||
// Open the git repo in the .git folder's parent, not the .git folder itself.
|
||||
repo, err := git.PlainOpen(path.Join(gitRoot, ".."))
|
||||
repo, err := git.PlainOpen(filepath.Dir(gitRoot))
|
||||
if err == git.ErrRepositoryNotExists {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -64,3 +64,6 @@ brew::
|
|||
go install -ldflags "-X github.com/pulumi/pulumi/sdk/v2/go/common/version.Version=${VERSION}" ${LANGUAGE_HOST}
|
||||
cp dist/pulumi-resource-pulumi-nodejs "$$(go env GOPATH)"/bin/
|
||||
cp dist/pulumi-analyzer-policy "$$(go env GOPATH)"/bin/
|
||||
|
||||
publish:: build_package
|
||||
bash -c ../../scripts/publish_npm.sh
|
||||
|
|
|
@ -52,3 +52,10 @@ dist::
|
|||
cp ./dist/pulumi-analyzer-policy-python "$$(go env GOPATH)"/bin/
|
||||
|
||||
brew:: dist
|
||||
|
||||
publish:: build_package
|
||||
twine upload \
|
||||
-u pulumi -p "${PYPI_PASSWORD}" \
|
||||
"env/src/dist"/*.whl \
|
||||
--skip-existing \
|
||||
--verbose
|
||||
|
|
Loading…
Reference in a new issue