diff --git a/DOCS.md b/DOCS.md index 78eb9f9..fc6547d 100644 --- a/DOCS.md +++ b/DOCS.md @@ -8,7 +8,7 @@ Use the PyPI plugin to deploy a Python package to a PyPI server. The following is an example configuration for your .drone.yml: ```yaml -deploy: +publish: pypi: repository: https://pypi.python.org/pypi username: guido diff --git a/main.go b/main.go index 5bc2736..22cef07 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ import ( "github.com/drone/drone-go/plugin" ) +// Params desribes how to upload a Python module to PyPI. type Params struct { Distributions []string `json:"distributions"` Password *string `json:"password,omitempty"` @@ -28,25 +29,28 @@ func main() { plugin.Param("vargs", &v) plugin.MustParse() - err := deploy(&w, &v) + err := v.Deploy(&w) if err != nil { log.Fatal(err) } } -func deploy(w *drone.Workspace, v *Params) error { - err := createConfig(v) +// Deploy creates a PyPI configuration file and uploads a module. +func (v *Params) Deploy(w *drone.Workspace) error { + err := v.CreateConfig() if err != nil { return err } - err = uploadDist(w, v) + err = v.UploadDist(w) if err != nil { return err } return nil } -func createConfig(v *Params) error { +// CreateConfig creates a PyPI configuration file in the home directory of +// the current user. +func (v *Params) CreateConfig() error { f, err := os.Create(path.Join(os.Getenv("HOME"), ".pypirc")) if err != nil { return err @@ -61,7 +65,8 @@ func createConfig(v *Params) error { return nil } -func uploadDist(w *drone.Workspace, v *Params) error { +// UploadDist executes a distutils command to upload a python module. +func (v *Params) UploadDist(w *drone.Workspace) error { cmd := v.Upload() cmd.Dir = w.Path cmd.Stdout = os.Stdout @@ -100,7 +105,7 @@ password: %s return err } -// Upload creates a setuptools upload command. +// Upload creates a distutils upload command. func (v *Params) Upload() *exec.Cmd { distributions := []string{"sdist"} if len(v.Distributions) > 0 { diff --git a/main_test.go b/main_test.go index 972ee65..7e0bb92 100644 --- a/main_test.go +++ b/main_test.go @@ -9,10 +9,30 @@ import ( "github.com/drone/drone-go/drone" ) -func TestDeploy(t *testing.T) { - w := drone.Workspace{ - Path: os.Getenv("DRONE_PYPI_PATH"), - } +// TestPublish checks if this module can successfully publish a PyPI +// package. A simple module is included in the `testdata` directory. +// +// To run this test against the PyPI test server: +// +// 1. register a new account (https://wiki.python.org/moin/TestPyPI) +// 2. Export DRONE_PYPI_PATH, DRONE_PYPI_REPOSITORY, DRONE_PYPI_USERNAME, +// DRONE_PYPI_PASSWORD, and DRONE_PYPI_DISTRIBUTIONS +// 3. Run the test suite +// +// For example: +// +// $ export DRONE_PYPI_PATH=testdata +// $ export DRONE_PYPI_REPOSITORY=https://testpypi.python.org/pypi +// $ export DRONE_PYPI_USERNAME=drone_pypi_test +// $ export DRONE_PYPI_PASSWORD=$uper$ecretPassword +// $ export DRONE_PYPI_DISTRIBUTIONS=sdist +// $ go test -run TestPublish +// +// > NOTE: PyPI will refuse to upload the same version of a module twice, +// > however setup.py still returns zero to the shell so this appears as a +// > successful test. +func TestPublish(t *testing.T) { + w := drone.Workspace{Path: os.Getenv("DRONE_PYPI_PATH")} repository := os.Getenv("DRONE_PYPI_REPOSITORY") username := os.Getenv("DRONE_PYPI_USERNAME") password := os.Getenv("DRONE_PYPI_PASSWORD") @@ -25,16 +45,13 @@ func TestDeploy(t *testing.T) { if w.Path == "" { t.Skip("DRONE_PYPI_PATH not set") } - err := deploy(&w, &v) + err := v.Deploy(&w) if err != nil { t.Error(err) } } -func sPtr(s string) *string { - return &s -} - +// TestConfig checks if a PyPI configuration file can be generated. func TestConfig(t *testing.T) { testdata := []struct { repository *string @@ -100,6 +117,8 @@ password: supersecret } } +// TestUpload checks if a distutils upload command can be properly +// formatted. func TestUpload(t *testing.T) { testdata := []struct { distributions []string @@ -127,3 +146,7 @@ func TestUpload(t *testing.T) { } } } + +func sPtr(s string) *string { + return &s +} diff --git a/testdata/.gitignore b/testdata/.gitignore new file mode 100644 index 0000000..5ae5013 --- /dev/null +++ b/testdata/.gitignore @@ -0,0 +1,3 @@ +*.egg-info/ +build/ +dist/ diff --git a/testdata/README b/testdata/README new file mode 100644 index 0000000..ac60f68 --- /dev/null +++ b/testdata/README @@ -0,0 +1 @@ +A simple test module diff --git a/testdata/drone_pypi/__init__.py b/testdata/drone_pypi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/testdata/setup.py b/testdata/setup.py new file mode 100644 index 0000000..1af5b8c --- /dev/null +++ b/testdata/setup.py @@ -0,0 +1,28 @@ +from setuptools import setup +import subprocess + + +def get_version(): + try: + git = subprocess.Popen( + ["git", "describe", "--long"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + except Exception: + return "0.0.0" + val = git.communicate()[0] + if git.returncode != 0: + return "0.0.0" + l = val.strip().split("-") + return l[0] + "." + l[1] + + +setup( + name="drone-pypi", + version=get_version(), + description="Module for testing drone-pypi.", + url="http://github.com/drone-plugins/drone-pypi", + packages=["drone_pypi"], + maintainer="Drone Contributors", + maintainer_email="support@drone.io", +)