From 766dc568b06e49afbb831c25a6163be31ab5064a Mon Sep 17 00:00:00 2001 From: Jared Nielsen Date: Thu, 5 Sep 2024 03:09:19 -0400 Subject: [PATCH 01/21] Add codehosting.png, fix broken link (#104) * add codehosting.png, fix broken link * delete linkcheck_ignore item --- custom_conf.py | 1 - explanation/code.rst | 2 +- images/codehosting.png | Bin 0 -> 61819 bytes 3 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 images/codehosting.png diff --git a/custom_conf.py b/custom_conf.py index 91957b7..e026b44 100644 --- a/custom_conf.py +++ b/custom_conf.py @@ -135,7 +135,6 @@ 'JavascriptUnitTesting/MockIo', # needs update 'PolicyAndProcess/Accessibility', # needs update 'Translations/Specs/UpstreamImportIntoUbuntu/FixingIsImported/setCurrentTranslation', # needs update - 'attachment:codehosting.png', # needs update 'https://git.launchpad.net/launchpad-mojo-specs/tree/mojo-lp-git/services', # private 'https://wiki.canonical.com/InformationInfrastructure/OSA/LaunchpadProductionStatus', # private 'https://wiki.canonical.com/Launchpad/PolicyandProcess/ProductionChange', # private diff --git a/explanation/code.rst b/explanation/code.rst index 7c59602..4ef6890 100644 --- a/explanation/code.rst +++ b/explanation/code.rst @@ -28,7 +28,7 @@ system. The major sub-systems are: Each of these subsystems also have multiple moving parts and some have other asynchronous jobs associated with them. -The `codehosting overview diagram `__ +The `codehosting overview diagram :attachment:../images/codehosting.png` summarises how some of these systems interact. You can `run the codehosting system diff --git a/images/codehosting.png b/images/codehosting.png new file mode 100644 index 0000000000000000000000000000000000000000..0cbffb5dac3877a981223f8f4782a06e14aa3936 GIT binary patch literal 61819 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 literal 0 HcmV?d00001 From eb5a0b185af6122720d44791aa8c98d52daf93e5 Mon Sep 17 00:00:00 2001 From: Jared Nielsen Date: Fri, 6 Sep 2024 04:00:51 -0400 Subject: [PATCH 02/21] remove accessibility, upstream, and schema links (#102) --- custom_conf.py | 3 --- explanation/engineering-overview-translations.rst | 7 +------ how-to/triage-bugs.rst | 12 ++++++------ 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/custom_conf.py b/custom_conf.py index e026b44..696e7f6 100644 --- a/custom_conf.py +++ b/custom_conf.py @@ -133,15 +133,12 @@ 'Debugging#Profiling%20page%20requests', # needs update 'Debugging#Special%20URLs', # needs update 'JavascriptUnitTesting/MockIo', # needs update - 'PolicyAndProcess/Accessibility', # needs update - 'Translations/Specs/UpstreamImportIntoUbuntu/FixingIsImported/setCurrentTranslation', # needs update 'https://git.launchpad.net/launchpad-mojo-specs/tree/mojo-lp-git/services', # private 'https://wiki.canonical.com/InformationInfrastructure/OSA/LaunchpadProductionStatus', # private 'https://wiki.canonical.com/Launchpad/PolicyandProcess/ProductionChange', # private 'https://wiki.canonical.com/Launchpad/PolicyandProcess/ProductionChangeApprovalPolicy', # private 'https://deployable.ols.canonical.com/project/launchpad-db', # private 'irc.libera.chat', # this is not an HTTP link - 'attachment:TranslationsSchema.dia', # needs update r'https://github\.com/canonical/fetch-service*', # private r'https://github\.com/canonical/fetch-operator*', # private 'https://git.launchpad.net/charm-launchpad-buildd-image-modifier/tree/files/scripts/setup-ppa-buildd', # private diff --git a/explanation/engineering-overview-translations.rst b/explanation/engineering-overview-translations.rst index b4cc1f7..1bd7932 100644 --- a/explanation/engineering-overview-translations.rst +++ b/explanation/engineering-overview-translations.rst @@ -315,9 +315,6 @@ Message sharing Objects and schema ------------------ -See my horrible `schema overview `__ -(dia format). - In a nutshell: - A \`POTemplate\` lives in either a \`ProductSeries\` or a @@ -370,9 +367,7 @@ A translation message can be in one of three sharing states: 3. **Tracking.** The translation is not only shared on one translation side, but between both translation sides. -We have a `design -document `__ -that specifies how messages in these states respond to changes. We try +We have a design document that specifies how messages in these states respond to changes. We try to make it easy to move a translation down this list (towards tracking) and hard to move up the list (towards diverged). diff --git a/how-to/triage-bugs.rst b/how-to/triage-bugs.rst index 728bdf1..fb157f3 100644 --- a/how-to/triage-bugs.rst +++ b/how-to/triage-bugs.rst @@ -16,8 +16,8 @@ We want: are dependencies of other critical bugs. - The *High* bugs list to be our main set of top priorities. Some specific sorts of bugs we always treat as high. Right now: OOPSes, - timeouts, A and AA `treat accessibility - bugs `__. + timeouts, A and AA treat accessibility + bugs. We would prefer to be able to treat OOPSes and timeouts as critical, as it was the case until 2020, but having a practically-usable Critical queue @@ -95,8 +95,8 @@ High These are bugs that will be our main focus in normal operation, timeouts (tagged "timeout"), OOPSes (thanks to our `zero OOPS policy `__, -and tagged "oops"), and A and AA conformance `accessibility -bugs `__. +and tagged "oops"), and A and AA conformance accessibility +bugs. Low ~~~ @@ -104,8 +104,8 @@ Low We mark as *Low* any bug that we recognise as legitimate but that is **not** a priority for Canonical staff to fix. This is not the same as planning not to fix the bug; it means that we don't know when we will -fix it, if at all. This includes AAA conformance `accessibility -bugs `__. +fix it, if at all. This includes AAA conformance accessibility +bugs. Others ~~~~~~ From ce5408a8ba919d22c5f5f01ff0396e1eb982d359 Mon Sep 17 00:00:00 2001 From: Jared Nielsen Date: Thu, 12 Sep 2024 08:11:00 -0400 Subject: [PATCH 03/21] add concepts.rst, fix broken link in code.rst (#105) * add concepts.rst, fix broken link in code.rst * add spellcheck errors to custom_wordlist * add concepts to index.rst --- .custom_wordlist.txt | 6 ++ custom_conf.py | 1 - explanation/code.rst | 4 +- explanation/concepts.rst | 148 +++++++++++++++++++++++++++++++++++++++ explanation/index.rst | 1 + 5 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 explanation/concepts.rst diff --git a/.custom_wordlist.txt b/.custom_wordlist.txt index d4a79e7..23015ae 100644 --- a/.custom_wordlist.txt +++ b/.custom_wordlist.txt @@ -1,5 +1,6 @@ activereviews adapter +adapters adapter's AddingLaunchpadCelebrity analyze @@ -40,6 +41,7 @@ Bionic's Blazingly bool boolean +BranchMergeProposal breakpoint browserconfig BrowserNotificationMessages @@ -103,6 +105,7 @@ DateTimeJSONEncoder DatetimeUsageGuide DavidAllouche DBEnums +DistributionSourcePackage dbpatches dbschema dbupgrade @@ -326,6 +329,7 @@ os OSA OWASP OWASP's +PackageBranchTarget PageSpeed pagespeed pagetest @@ -334,6 +338,7 @@ pagetests pamola PatchSubmission pdb +PersonBranchTarget pentested performant pgbouncer @@ -383,6 +388,7 @@ pre_iter_hook prioritize prober proc +ProductBranchTarget ProductSeries programmatically prometheus diff --git a/custom_conf.py b/custom_conf.py index 696e7f6..c36f640 100644 --- a/custom_conf.py +++ b/custom_conf.py @@ -127,7 +127,6 @@ 'https://wiki.canonical.com/InformationInfrastructure/OSA/LPHowTo/ManualCdImageMirrorProber', # private 'Trunk/Glue', # needs update '/Background', - '/Concepts', # needs update '/HowToUseCodehostingLocally', # needs update 'Database/TableRenamePatch', # needs update 'Debugging#Profiling%20page%20requests', # needs update diff --git a/explanation/code.rst b/explanation/code.rst index 4ef6890..a30e955 100644 --- a/explanation/code.rst +++ b/explanation/code.rst @@ -136,9 +136,7 @@ kicked off. The web application ------------------- -Code that is executed as part of the Launchpad web application. The core -`concepts `__ are documented on the -`Code/Concepts `__ page. +Code that is executed as part of the Launchpad web application. The core concepts are documented on the :doc:`Code Concepts <./concepts>` page. **Major features** diff --git a/explanation/concepts.rst b/explanation/concepts.rst new file mode 100644 index 0000000..c9c6074 --- /dev/null +++ b/explanation/concepts.rst @@ -0,0 +1,148 @@ +Code Concepts +============= + +In order to fully understand the **\`lp.code\`** modules, it helps to +have an understanding of a number of core concepts. + +Registry objects are those Launchpad-wide objects that are shared +between the different Launchpad applications. The registry objects that +**\`lp.code\`** modules are associated with are: + +- Person +- Product +- Project +- !SourcePackage +- Distribution +- !DistroSeries +- !DistributionSourcePackage + +``  ''Please be aware of the confusion between ``\ *:literal:`\`Products\``*\ `` and ``\ *:literal:`\`Projects\``*\ `` in the codebase.  To the outside world a ``\ *:literal:`\`Product\``*\ `` is a project, and a ``\ *:literal:`\`Project\``*\ `` is a project group (or super-project).''`` + +There are a few major concepts in **\`lp.code\`** to do with branches: + +- `Branch <#branch>`__ +- `Merge proposal <#merge-proposal>`__ +- `Namespace <#namespace>`__ +- `Target <#target>`__ +- `Collection <#collection>`__ + +<> + +Branch +------ + +The branch object in Launchpad refers to a real Bazaar branch. + +A branch has an owner. The owner can be either an individual or a team. +The owner defines who can write to the branch. + +A branch also has a target. There are three current targets: + +- !PersonBranchTarget - these are \`+junk\` branches +- !ProductBranchTarget - these are branches associated with a product, + sometimes called an upstream +- !PackageBranchTarget - these branches are associated with source + packages. A source package is effectively tuple of a particular + package name in a distribution series. + +You almost never need to know about these objects though, since they are +!IBranchTarget adapters: \`IBranchTarget(person)`, +\`IBranchTarget(product)`, \`IBranchTarget(source_package)`. + +A branch also has a name. + +Together the owner, target and name make the \`unique_name\` of the +branch. + +<> + +Merge proposal +-------------- + +A merge proposal (`BranchMergeProposal`) is used to record information +around the process of merging one branch into another. + +In situations where feature branches are used, it is normal for each +feature branch to have a merge proposal for the main trunk branch. In +these cases the feature branch is the \`source_branch`, and the trunk is +the \`target_branch`. + +The code review process happens around a merge proposal. People can +review and comment on the proposal, and proposals can be approved (or +rejected) to land on the target branch. + +<> + +Namespace +--------- + +A namespace is (usually?) an owner and a target. + +A namespace has exactly one branch collection associated with it. In +some sense, it **is** a branch collection. (is-a could mean inheritance +or adaptation). + +A namespace is, conceptually, everything up to the last part of a +branch's unique name. + +There's no hierarchy of branches beneath a namespace. + +A branch belongs to exactly one namespace. + +:: + + IBranchNamespace + target :: IBranchTarget + getBranches() :: [IBranch] + createBranch(*args) :: IBranch + +<> + +Target +------ + +**Target** is the most nebulous of these concepts. A target is a thing a +branch is a branch \*of*, or perhaps a thing a branch lives on. A +product is a target, a source package is a target, a person's +junk area +is a target. A project (i.e. a collection of products) is not a target. + +Each branch has exactly one target. + +A target is not a namespace (in general). A +junk target is, at some +level, a namespace, but other targets are not (only because +junk is +associated with a person). + +A target has a collection naturally associated with it: the collection +of all branches with that target. Does this mean a target is, in some +sense, a collection? Probably not. + +:: + + IBranchTarget + context :: (registry object) + collection :: IBranchCollection + default_stacked_on_branch :: IBranch + default_merge_target :: IBranch + getNamespace(person) :: IBranchNamespace + -- implemented by BranchTarget only. + +<> + +Collection +---------- + +A collection has no semantic value beyond being a collection. It need +not be tied to a specific registry object, namespace or target. "All +branches" is a special, well-known branch collection. A collection is +simply a clear API for "a bunch of branches". A collection is the +preferred way of talking about a bunch of branches in our code-base. + +:: + + IBranchCollection + getBranches + getMergeProposals + - implemented using getBranches, + - merge proposals where the source branch is in getBranches() + # separately, + # a bunch of filter methods. \ No newline at end of file diff --git a/explanation/index.rst b/explanation/index.rst index d29d619..b82970e 100644 --- a/explanation/index.rst +++ b/explanation/index.rst @@ -38,6 +38,7 @@ General error-explanations security-policy xxx-policy + concepts JavaScript ---------- From b2e88bda27173c92a1f2620abdd7bc77c302a794 Mon Sep 17 00:00:00 2001 From: Tushar <30565750+tushar5526@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:36:12 +0530 Subject: [PATCH 04/21] Update manage-users.rst (#100) Update the steps to run anoint-team-members --- how-to/manage-users.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/how-to/manage-users.rst b/how-to/manage-users.rst index 9c9239e..3442d10 100644 --- a/how-to/manage-users.rst +++ b/how-to/manage-users.rst @@ -38,17 +38,20 @@ For staging and qastaging we should: 1. SSH into ``launchpad-bastion-ps5``, and switch to the ``stg-launchpad`` user by running ``sudo -iu stg-launchpad``. -2. SSH into the ``launchpad-scripts`` juju unit, by running +2. SSH into the ``launchpad-admin`` juju unit, by running ``in-model qastaging juju ssh launchpad-scripts/leader``. -3. Add the user to the team by running: +3. Switch to ``launchpad`` user, by running +``sudo su launchpad``. + +4. Add the user to the team by running: .. code:: - /srv/launchpad/code/utilities/anoint-team-member + LPCONFIG=launchpad-admin /srv/launchpad/code/utilities/anoint-team-member In our example: .. code:: - /srv/launchpad/code/utilities/anoint-team-member test-user admins + LPCONFIG=launchpad-admin /srv/launchpad/code/utilities/anoint-team-member test-user admins From 89fe71311bdad0353caef1ff66ec67630c34e52a Mon Sep 17 00:00:00 2001 From: Tushar <30565750+tushar5526@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:24:42 +0530 Subject: [PATCH 05/21] Update database-schema-changes-process.rst (#114) Fix RST errors. --- how-to/database-schema-changes-process.rst | 115 ++++++++++----------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/how-to/database-schema-changes-process.rst b/how-to/database-schema-changes-process.rst index 2989292..35d7424 100644 --- a/how-to/database-schema-changes-process.rst +++ b/how-to/database-schema-changes-process.rst @@ -9,8 +9,6 @@ Step-by-step procedure 1. Prepare a branch containing just `your database patch <#Making_a_database_patch>`__ for review. -- - - The patch must either be a hot patch (function / trigger / index) or a cold patch (model change / model change + function/trigger). If you need both hot and cold changes, you require multiple @@ -18,7 +16,7 @@ Step-by-step procedure 2. Submit a merge proposal for your branch, requesting a **db** review from launchpad-reviewers. For hot patches the target branch is - \`master`, but for cold patches it should be \`db-devel`. + ``master``, but for cold patches it should be ``db-devel``. 3. Iterate on the branch as needed. The DB review process can sometimes require significant changes to achieve acceptable performance on @@ -35,7 +33,7 @@ Step-by-step procedure in stable and not yet deployed to all affected service instances. -6. Land the branch on \`master\` (for hot patches) or \`db-devel\` (for +6. Land the branch on ``master`` (for hot patches) or ``db-devel`` (for cold patches) by setting the merge proposal to Approved as usual, unless someone has stated it is being landed it on your behalf. (Only Canonical staff can do the landing step). @@ -47,7 +45,7 @@ Step-by-step procedure 8. [Cold patches] After the branch reaches staging check the duration that the patch took to apply by rsyncing - \`pamola.internal::staging-logs/dbupgrade.log\` from carob. If it + ``pamola.internal::staging-logs/dbupgrade.log`` from carob. If it took more than 15 seconds, mark the revision bad and revert it. 9. [Cold patches] QA the patch as usual, check things still work on @@ -81,8 +79,8 @@ other. Test \*only\* code may be included if absolutely necessary. Exceptions to this rule require approval from the project lead, because deploying them will require a 1 hour plus complete downtime window. -Cold schema patches always land on \`db-devel`. After they are made live -they will be promoted to \`master\` as part of the go-live process. +Cold schema patches always land on ``db-devel``. After they are made live +they will be promoted to ``master`` as part of the go-live process. Hot Patches ~~~~~~~~~~~ @@ -120,15 +118,15 @@ Reviews ------- All schema changes should have reviews of type "db" requested from the -regular review team (`launchpad-reviewers`). An approve vote from any DB +regular review team (``launchpad-reviewers``). An approve vote from any DB reviewer is sufficient to land the patch. As schema changes have no appserver code changes landed at the same time, no other reviews are needed (unless an exception to the no-mixing rule has been granted, in which case a normal review is also needed). -Changes to the permissions in \`database/schema/security.cfg\` or the -comments in \`database/schema/comments.sql\` are not schema patches and +Changes to the permissions in ``database/schema/security.cfg`` or the +comments in ``database/schema/comments.sql`` are not schema patches and do not require db review when done on their own. If they are included in a schema patch then the db reviewer will review them. @@ -138,7 +136,7 @@ Patch ids The schema application code needs a unique id for each patch. This is allocated by editing a shared document stored in the `dbpatches repository `__. If -you are in \`~launchpad\` please allocate this yourself. Other +you are in ``~launchpad`` please allocate this yourself. Other developers can ask any ~launchpad member to allocate a patch number for them. @@ -153,16 +151,16 @@ Making a database patch You need to run these steps whenever you make a schema change, regardless of whether you intend to delete sample data or not. For -example, if you are adding a new column to the \`Person\` table, these +example, if you are adding a new column to the ``Person`` table, these steps ensure that the sample data will include this new column. -1. **Run \`make schema\` to get a pristine database of sample data.** +1. Run ``make schema`` to get a pristine database of sample data. 2. Claim a patch number in `the dbpatches repository `__ - (be sure to commit and push back to the \`main\` branch). + (be sure to commit and push back to the ``main`` branch). -# Create a SQL file in \`database/schema/\` containing the changes you +# Create a SQL file in ``database/schema/`` containing the changes you want. It should look like this: :: @@ -177,54 +175,54 @@ want. It should look like this: INSERT INTO LaunchpadDatabaseRevision VALUES (XXXX, YY, Z); 3. Run your new SQL patch on the development database to ensure that it - works. Do this by running \`psql launchpad_dev -1 -f your-patch.sql\` + works. Do this by running ``psql launchpad_dev -1 -f your-patch.sql`` -4. Run \`psql launchpad_ftest_playground -f your-patch.sql\` as the +4. Run ``psql launchpad_ftest_playground -f your-patch.sql`` as the ftest playground db is used to regenerate sampledata snapshots in the - following step. (Also be sure you ran \`psql launchpad_dev -f - your-patch.sql\` in the previous step-- this updates the dev + following step. (Also be sure you ran ``psql launchpad_dev -f + your-patch.sql`` in the previous step-- this updates the dev database's sampledata. Note that this is *not* sufficient to let the test suite see your changes: for that, you'll need to update - \`launchpad_ftest_template`, though it's simplest to run \`make - schema\` or \`make -C database/schema test\` as described below.) + ``launchpad_ftest_template``, though it's simplest to run ``make + schema`` or ``make -C database/schema test`` as described below.) -5. You may wish to run \`make newsampledata`, although it isn't +5. You may wish to run ``make newsampledata``, although it isn't critical; this will let you see what changes your patch would make to initial setups. -``   1. This will produce a lot of noise. Feel free to ignore it.`` + - This will produce a lot of noise. Feel free to ignore it. -6. Review the sample data changes that occurred using \`git diff - database/sampledata`. This diff can be hard to review as-is. You - might want to use a graphical diff viewer like \`kompare\` or - \`meld\` which will make it easier. Make sure that you understand all +6. Review the sample data changes that occurred using ``git diff + database/sampledata``. This diff can be hard to review as-is. You + might want to use a graphical diff viewer like ``kompare`` or + ``meld`` which will make it easier. Make sure that you understand all the changes you see. -7. Move your pending SQL file into \`database/schema/\` with a name like - \`patch-xx-yy-zz.sql\` (where *xx* matches the existing patches), and - ending with the line \`INSERT INTO LaunchpadDatabaseRevision VALUES - (xx, yy, zz);`. +7. Move your pending SQL file into ``database/schema/`` with a name like + ``patch-xx-yy-zz.sql`` (where *xx* matches the existing patches), and + ending with the line ``INSERT INTO LaunchpadDatabaseRevision VALUES + (xx, yy, zz);``. 8. If you have removed or renamed a table or column, ensure that your - patch includes appropriate \`COMMENT\` statements. + patch includes appropriate ``COMMENT`` statements. -9. **Run \`make schema\` again to ensure that it works, and that you now +9. **Run** ``make schema`` **again to ensure that it works, and that you now have a pristine database with the new sample data.** If you don't - want to blow away your \`launchpad_dev\` database, then you can use - \`make -C database/schema test\` instead to update only the test + want to blow away your ``launchpad_dev`` database, then you can use + ``make -C database/schema test`` instead to update only the test databases. -10. New tables and columns need corresponding \`COMMENT\` statements in +10. New tables and columns need corresponding ``COMMENT`` statements in your patch. -11. Make any necessary changes to \`database/schema/fti.py`, - \`database/schema/security.cfg`. +11. Make any necessary changes to ``database/schema/fti.py``, + ``database/schema/security.cfg``. 12. **Run the full test suite to ensure that your new schema doesn't break any existing tests/code by side effect.** 13. Commit without sample data changes, push and propose for merging to - \`db-devel\` + ``db-devel`` Rules for patches ~~~~~~~~~~~~~~~~~ @@ -232,9 +230,9 @@ Rules for patches 1. Don't use the TRUNCATE or DROP TABLE statements as they don't work with Slony-I replication. -2. To drop a table, move it into the \`todrop\` namespace using a - statement like \`ALTER TABLE FooBar SET SCHEMA todrop`. Then - \`upgrade.py\` will automatically drop these tables during the +2. To drop a table, move it into the ``todrop`` namespace using a + statement like ``ALTER TABLE FooBar SET SCHEMA todrop``. Then + ``upgrade.py`` will automatically drop these tables during the downtime. Be careful about foreign keys: the drop order is undefined so foreign keys between the tables must be dropped explicitly, and foreign keys handled specially by application code (most branch and @@ -243,13 +241,12 @@ Rules for patches 3. Do not migrate data in schema patches unless the data size is extraordinarily small (< 100's of rows). - 4. Similarly, new columns must default NULL unless the data size is extraordinarily small (< 100's of rows). 5. When changing existing DB functions, start your patch with the - original version (`SELECT pg_get_functiondef(oid) FROM pg_proc WHERE - proname IN ('foofunc', 'barfunc') ORDER BY proname;`). This makes it + original version (``SELECT pg_get_functiondef(oid) FROM pg_proc WHERE + proname IN ('foofunc', 'barfunc') ORDER BY proname;``). This makes it much easier to review the diff. Sample data @@ -266,7 +263,7 @@ In fact, there are now two sets of sampledata that need to be updated. We use sample data to provide well-known baseline data for the test suite, and to populate a developer's Launchpad instance so that -\`launchpad.dev\` can display interesting stuff. There are some +``launchpad.dev`` can display interesting stuff. There are some guidelines and recommendations you should be aware of before you make changes to the test suite sample data, or you may break the tests for yourself or others. @@ -279,25 +276,25 @@ test's harness instead of adding new sample data. This will often make the tests themselves more readable because you're not relying on magical values in the sample database. Doing it this way also reduces the chance that your changes will break other tests by side-effect. Add the new -data in your test's \`setUp()\` or in the narrative of your doctest. -Because the test suite uses the \`launchpad_ftest_template\` database, +data in your test's ``setUp()`` or in the narrative of your doctest. +Because the test suite uses the ``launchpad_ftest_template`` database, there is no chance that running the test suite will accidentally alter the sample data. -However, if you interact with the web U/I for \`launchpad.dev\` your -changes will end up in the \`launchpad_dev\` database. This database is +However, if you interact with the web U/I for ``launchpad.dev`` your +changes will end up in the ``launchpad_dev`` database. This database is used to create the new sample data, so it is imperative that you run -\`make schema\` to start with a pristine database before generating new +``make schema`` to start with a pristine database before generating new sample data. If in fact you do want the effects of your u/i interactions to land in the new sample data, then the general process is to -- run \`make schema\` -- interact with \`launchpad.dev\` -- follow the \`make newsampledata\` steps above. +- run ``make schema`` +- interact with ``launchpad.dev`` +- follow the ``make newsampledata`` steps above. **Be aware though that your generation of new sample data will probably have an effect on tests not related to your changes!** For example, if -you generate new karma events, you will break the \`karma_sample_data\` +you generate new karma events, you will break the ``karma_sample_data`` tests because they expect all karma events to be dated prior to the year 2002. If you make changes to the sample data, you **must** run the full test suite and ensure that you get no failures, otherwise there is a @@ -306,9 +303,9 @@ very high likelihood that you will break the trunk. Resolving schema conflicts ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Resolving conflicts in \`current.sql\` manually is usually more trouble +Resolving conflicts in ``current.sql`` manually is usually more trouble than it's worth. Instead, first resolve any conflicts in -\`comments.sql`, then: +``comments.sql``, then: :: @@ -327,8 +324,8 @@ than it's worth. Instead, first resolve any conflicts in Notes on Changing security.cfg ------------------------------ -It is possible to land changes to security.cfg on \`master\` rather than -\`db-devel`. These changes are deployed during no-downtime rollouts. +It is possible to land changes to security.cfg on ``master`` rather than +``db-devel``. These changes are deployed during no-downtime rollouts. Note that adding new users requires manual DB reconfiguration, so you need to file an RT ticket to grant access to relevant machines and make From 48db285825ab516704463ea3d41040921c48cf10 Mon Sep 17 00:00:00 2001 From: Ines Almeida Date: Sun, 29 Sep 2024 09:35:12 +0200 Subject: [PATCH 06/21] Fix steps to anoint team members --- how-to/manage-users.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/how-to/manage-users.rst b/how-to/manage-users.rst index 3442d10..5a44beb 100644 --- a/how-to/manage-users.rst +++ b/how-to/manage-users.rst @@ -39,19 +39,16 @@ For staging and qastaging we should: user by running ``sudo -iu stg-launchpad``. 2. SSH into the ``launchpad-admin`` juju unit, by running -``in-model qastaging juju ssh launchpad-scripts/leader``. +``in-model qastaging juju ssh launchpad-admin/leader``. -3. Switch to ``launchpad`` user, by running -``sudo su launchpad``. - -4. Add the user to the team by running: +3. Add the user to the team by running: .. code:: - LPCONFIG=launchpad-admin /srv/launchpad/code/utilities/anoint-team-member + /srv/launchpad/code/utilities/anoint-team-member In our example: .. code:: - LPCONFIG=launchpad-admin /srv/launchpad/code/utilities/anoint-team-member test-user admins + /srv/launchpad/code/utilities/anoint-team-member test-user admins From f46ff8677d44f7fa051117e431b124f8ed221b08 Mon Sep 17 00:00:00 2001 From: Simone Pelosi Date: Mon, 30 Sep 2024 15:39:55 +0200 Subject: [PATCH 07/21] Documentation to generate Api Docs on Launchpad --- .wordlist.txt | 3 ++ how-to/launchpad-api-docs.rst | 59 +++++++++++++++++++++++++++ how-to/launchpad-development-tips.rst | 1 + 3 files changed, 63 insertions(+) create mode 100644 how-to/launchpad-api-docs.rst diff --git a/.wordlist.txt b/.wordlist.txt index 7e4aa3e..40c8034 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -76,11 +76,14 @@ TODO Triaging tzinfo UI +URL undercommunication updateable VM +xls xUnit XXXes YAML YUI +wadl zpt diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst new file mode 100644 index 0000000..b8fbb00 --- /dev/null +++ b/how-to/launchpad-api-docs.rst @@ -0,0 +1,59 @@ +Launchpad API Docs generation +============================= + +The Launchpad API documentation portal is available at +``_. It contains summaries of the different +web service versions, and links to version-specific documents. + +To define our web resources we are using the +`lazr.restful `_ +decorators and capabilities. These decorators are also responsible to generate +the related documentation for the exported field. + +We can build Api Docs using ``make apidoc`` command: this command will +generate the documentation under ``lib/canonical/launchpad/apidoc``. +Note that we should delete the aforementioned folder in order to generate +fresh docs. + +The command above is responsible to call the +``utilities/create-lp-wadl-and-apidoc.py`` script and generate the related +documentation using the ``lp.services.webservice.wadl`` module utilities. + +This scripts will create the related ``wadl`` and then it will translated to +``HTML``. During this process ``generate_html`` function will be called: this +function is responsible to map ``wadl`` entries to ``HTML``. +To do that we use as template the file called ``wadl-to-refhtml.xsl``: in +this file we can also apply patches to fix not-well generated entry points +for given ``wadl`` entries. + +Example +~~~~~~~ + +For example for the ``SocialAccount`` webservice we used the +``@exported_as_webservice_entry("social_account", as_of="beta")`` decorator. +Thanks to that the ``social_account`` entry is created. +We can use the aforementioned id to refer this ``wadl`` entry in the ``wadl-to-refhtml.xls`` file. + +Let's say that we want to change the entry URL +from ``URL: https://api.launchpad.net/beta/`` +to ``URL: https://api.launchpad.net/beta//+socialaccount/``: +we should create an entry inside the ``find-entry-uri`` template inside the +``wadl-to-refhtml.xls`` file and we should search our ``wadl`` entry using the +``social_account`` id. After that we can write ``xls`` code that will append the +right string to the ``$base`` URL: + +.. code-block:: html + + + + + + / + <person.name> + /+socialaccount/ + <id> + + + + +The resulting URL will be: ``URL: https://api.launchpad.net/beta//+socialaccount/`` diff --git a/how-to/launchpad-development-tips.rst b/how-to/launchpad-development-tips.rst index 135168e..192fad6 100644 --- a/how-to/launchpad-development-tips.rst +++ b/how-to/launchpad-development-tips.rst @@ -14,3 +14,4 @@ Launchpad development tips chameleon debug-tests-with-visual-studio-code debug-buildfarm-builder + launchpad-api-docs From e2f582587bc13f71e6be42a171ac2b9b88f579c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 30 Sep 2024 11:30:03 +0200 Subject: [PATCH 08/21] Update instructions on how to get hold of the fetch service logs --- reference/services/fetch-service.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/reference/services/fetch-service.rst b/reference/services/fetch-service.rst index a37e0b4..6bc54a3 100644 --- a/reference/services/fetch-service.rst +++ b/reference/services/fetch-service.rst @@ -132,14 +132,18 @@ Qastaging ~~~~~~~~~ Currently, to access the fetch-service internal logs, one needs to: -1. SSH into ``stg-lp-fetch-service-qastaging@launchpad-bastion-ps5``. +1. SSH into Launchpad's bastion and switch to the following user: + ``stg-lp-fetch-service-qastaging@launchpad-bastion-ps5``. -2. SSH into the fetch-service juju unit by running ``juju ssh ``, for - example ``juju ssh fetch-service/2``. +2. SSH into the fetch-service juju unit by running + ``juju ssh fetch-service/leader``. 3. Run ``sudo snap logs fetch-service -n 100 -f`` (where ``-n`` sets the number of log lines, and ``-f`` keeps up the latest logs up-to-date). +Alternatively, you can also check the logs in the following directory: +``/var/snap/fetch-service/current``. + Monitoring ---------- Not set up. From 1fcb3a9588bcb62132ce0004bb98f54e28c6561c Mon Sep 17 00:00:00 2001 From: Nathan Barbarick Date: Mon, 30 Sep 2024 11:08:39 -0700 Subject: [PATCH 09/21] Group articles of the Explanation section into proper subsections (#97) * Remove How to go about writing a web application, per jugmac00. * Group articles in the Explanation section into subsections, add introductory text. * Add new sections for remaining ToC headings. * Add codehosting.png, fix broken link (#104) * add codehosting.png, fix broken link * delete linkcheck_ignore item * remove accessibility, upstream, and schema links (#102) * add concepts.rst, fix broken link in code.rst (#105) * add concepts.rst, fix broken link in code.rst * add spellcheck errors to custom_wordlist * add concepts to index.rst * Add descriptions in the explanation index and move new concepts page. --------- Co-authored-by: Jared Nielsen --- .../best-practices-for-development.rst | 12 + explanation/concepts.rst | 1 + explanation/database.rst | 11 + .../developing-the-launchpad-project.rst | 13 + explanation/ideas-behind-launchpad.rst | 10 + explanation/index.rst | 110 +++--- explanation/javascript.rst | 9 + explanation/parts-of-launchpad.rst | 13 + explanation/security-policy.rst | 4 +- ...setting-up-and-understanding-launchpad.rst | 13 + explanation/static-assets.rst | 10 + explanation/webapp-process.rst | 353 ------------------ 12 files changed, 153 insertions(+), 406 deletions(-) create mode 100644 explanation/best-practices-for-development.rst create mode 100644 explanation/database.rst create mode 100644 explanation/developing-the-launchpad-project.rst create mode 100644 explanation/ideas-behind-launchpad.rst create mode 100644 explanation/javascript.rst create mode 100644 explanation/parts-of-launchpad.rst create mode 100644 explanation/setting-up-and-understanding-launchpad.rst create mode 100644 explanation/static-assets.rst delete mode 100644 explanation/webapp-process.rst diff --git a/explanation/best-practices-for-development.rst b/explanation/best-practices-for-development.rst new file mode 100644 index 0000000..2ca3f97 --- /dev/null +++ b/explanation/best-practices-for-development.rst @@ -0,0 +1,12 @@ +Best practices for development +============================== + +.. toctree:: + :maxdepth: 1 + + architecture + charms + codeimport + performance + template-reuse + security-policy \ No newline at end of file diff --git a/explanation/concepts.rst b/explanation/concepts.rst index c9c6074..8122b9a 100644 --- a/explanation/concepts.rst +++ b/explanation/concepts.rst @@ -1,3 +1,4 @@ +============= Code Concepts ============= diff --git a/explanation/database.rst b/explanation/database.rst new file mode 100644 index 0000000..e490fb5 --- /dev/null +++ b/explanation/database.rst @@ -0,0 +1,11 @@ +Database +========= + +.. toctree:: + :maxdepth: 1 + + postgresql + working-with-db-devel + live-patching + storm-migration-guide + database-performance \ No newline at end of file diff --git a/explanation/developing-the-launchpad-project.rst b/explanation/developing-the-launchpad-project.rst new file mode 100644 index 0000000..e8611cd --- /dev/null +++ b/explanation/developing-the-launchpad-project.rst @@ -0,0 +1,13 @@ +Developing the Launchpad project +================================ + +.. toctree:: + :maxdepth: 1 + + branches + pre-merge-reviews + error-explanations + hacking + feature-flags + datetime-usage + xxx-policy \ No newline at end of file diff --git a/explanation/ideas-behind-launchpad.rst b/explanation/ideas-behind-launchpad.rst new file mode 100644 index 0000000..3619da2 --- /dev/null +++ b/explanation/ideas-behind-launchpad.rst @@ -0,0 +1,10 @@ +The ideas behind Launchpad +========================== + +.. toctree:: + :maxdepth: 1 + + scope + strategy + values + security diff --git a/explanation/index.rst b/explanation/index.rst index b82970e..a5b5552 100644 --- a/explanation/index.rst +++ b/explanation/index.rst @@ -1,74 +1,82 @@ Explanation =========== -General -------- +The ideas behind Launchpad +--------------------------- + +Explore these pages for an overview of the concepts and motivations behind the Launchpad project. .. toctree:: - :maxdepth: 1 - - running-details - framework - navigating - architecture - pip - charms - codeimport - performance - security - malone - scope - strategy - values - webapp-process - hacking - engineering-overview-translations - registry - code - url-traversal - template-reuse - navigation-menus - mail - feature-flags - branches - pre-merge-reviews - launchpad-ppa - testing - datetime-usage - error-explanations - security-policy - xxx-policy - concepts + :maxdepth: 2 + + ideas-behind-launchpad + +Setting up and understanding Launchpad +--------------------------------------- + +Understanding how to install and configure Launchpad, navigate the codebase, and test your changes will help you make meaningful contributions to the project. + +.. toctree:: + :maxdepth: 2 + + setting-up-and-understanding-launchpad + +Best practices for development +------------------------------- + +By using these principled approaches to development, you can improve Launchpad in a way that is sustainable and maintainable. + +.. toctree:: + :maxdepth: 2 + + best-practices-for-development + +Developing the Launchpad project +-------------------------------- + +These pages help explain important aspects of the developer experience. + +.. toctree:: + :maxdepth: 2 + + developing-the-launchpad-project + +Parts of Launchpad +------------------ + +After understanding the goals and approaches of the project, dive into the details by exploring the below components of the application. + +.. toctree:: + :maxdepth: 2 + + parts-of-launchpad JavaScript ---------- +These pages explain how to develop, test, and build using the YUI Test framework. + .. toctree:: - :maxdepth: 1 + :maxdepth: 2 - javascript-integration-testing - javascript-unittesting - javascript-buildsystem + javascript Static assets ------------- +Launchpad's visual style is controlled by CSS and images that you set up and build. + .. toctree:: - :maxdepth: 1 + :maxdepth: 2 - css - css-sprites - images - favicon + static-assets Database -------- +This section gives an overview of how Launchpad interacts with the PostgreSQL database. + .. toctree:: - :maxdepth: 1 + :maxdepth: 2 - postgresql - working-with-db-devel - live-patching - storm-migration-guide - database-performance + database diff --git a/explanation/javascript.rst b/explanation/javascript.rst new file mode 100644 index 0000000..fab45a4 --- /dev/null +++ b/explanation/javascript.rst @@ -0,0 +1,9 @@ +JavaScript +=========== + +.. toctree:: + :maxdepth: 1 + + javascript-integration-testing + javascript-unittesting + javascript-buildsystem diff --git a/explanation/parts-of-launchpad.rst b/explanation/parts-of-launchpad.rst new file mode 100644 index 0000000..ab072ce --- /dev/null +++ b/explanation/parts-of-launchpad.rst @@ -0,0 +1,13 @@ +Parts of Launchpad +=================== + +.. toctree:: + :maxdepth: 1 + + navigation-menus + mail + url-traversal + malone + registry + engineering-overview-translations + code \ No newline at end of file diff --git a/explanation/security-policy.rst b/explanation/security-policy.rst index 1906f92..6353f36 100644 --- a/explanation/security-policy.rst +++ b/explanation/security-policy.rst @@ -1,5 +1,5 @@ -Launchpad Security Policy -========================= +Launchpad permissions +====================== .. include:: ../includes/important_not_revised.rst diff --git a/explanation/setting-up-and-understanding-launchpad.rst b/explanation/setting-up-and-understanding-launchpad.rst new file mode 100644 index 0000000..e81eabd --- /dev/null +++ b/explanation/setting-up-and-understanding-launchpad.rst @@ -0,0 +1,13 @@ +Setting up and understanding Launchpad +======================================= + +.. toctree:: + :maxdepth: 1 + + running-details + framework + navigating + pip + launchpad-ppa + testing + concepts diff --git a/explanation/static-assets.rst b/explanation/static-assets.rst new file mode 100644 index 0000000..9474395 --- /dev/null +++ b/explanation/static-assets.rst @@ -0,0 +1,10 @@ +Static Assets +============== + +.. toctree:: + :maxdepth: 1 + + css + css-sprites + images + favicon \ No newline at end of file diff --git a/explanation/webapp-process.rst b/explanation/webapp-process.rst deleted file mode 100644 index abe63d6..0000000 --- a/explanation/webapp-process.rst +++ /dev/null @@ -1,353 +0,0 @@ -========================================= -How to go about writing a web application -========================================= - --- Steve Alexander - -.. include:: ../includes/important_out_of_date.rst - - -Introduction ------------- - -This document presents an approach to constructing web applications, -emphazising well-designed user interaction. - -In summary, we write a web application by - -1. Design the database that lies behind the web application - - Entity relationship models - - SQL statements -2. Design the web application's user interface - - Table of URLs (see later) - - Page template mock-ups -3. Write the Interfaces that the application will use to access the database - - interfaces.py files -4. Write the code and templates of the application - - page templates - - supporting classes - - application components - -Of course, this isn't a completely linear process. Steps may be carried out -in parallel, and ongoing work in each step will feed into the other steps. - -So that we can make rapid progress, and learn about the application as early -as possible, we should do steps 2, 3 and 4 focusing on just a few URLs at -a time (say, five or so). Then, when those are finished, we can make any -necessary changes to the database model, and then repeat steps 2, 3 and 4 -with some new URLs and new application functionality. - - - -Web application architecture ----------------------------- - -For the purposes of this document, a web application is put together as -follows:: - - +--------------------------------------------------------------------------+ - | { Amorphous cloud of URLs } | - | URLS { /rosetta/foo/bar/baz.html } | - | { } | - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | - | { Pages SubURLs | - | PRESENTATION { Views Templates | - | { Traversal Support classes | - | | - | WEB APP ------------------------------------------------- Interfaces | - | | - | APPLICATION { Utilities Components | - | COMPONENTS { Adapters | - | | - | | - | LIBRARIES { Python standard library | - | { Other libraries | - | | - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | - | | - | DATABASE relations, fields, constraints | - +--------------------------------------------------------------------------+ - -The boundaries of our web application are URLs at the top and the database -at the bottom. So, we must carefully define these things that lie at the -boundaries, so that we can work out what must go in the middle. - -URLs ----- - -URLs are the boundary between the web application and web browsers. When you -point a web browser at a URL, you'll get one of the following: - -- page -- form -- image or other data -- redirect -- "not found" error -- "unauthorized" error - -We'll be mostly concerned with pages, forms and redirects. We'll be concerned -with image and other data only when they are "managed content" and not just -part of the skin of the site. The photograph of a member of the site is an -example of managed content: it is stored in the database and may be -manipulated through using the application. CSS files, javascript files, -icons and logos are typically elements that make up the "skin" of the -application, and are not managed through the application. - -Another example of image or other data that is managed content is if we want -to allow users to download a .po or .pot file of translations. - -Forms are rendered in HTML and will typically be "self-posting forms". That -is, the address posted to when the [submit] button is pressed will be the -same as the address the page was got from. This allows browsers' bookmarks -to work properly, allows us to straightforwardly validate data entered into -the form, and keeps the URL space neat. - -The "not found" error is the familiar "404 Not Found" given when someone -tries to access a URL that is not known by our system. - -An "unauthorized" error means that accessing the given URL requires some -authentication. The browser will prompt the user to provide some additional -authentication. Alternatively, if we use other login schemes than HTTP Basic -or HTTP Digest, then the web application may present a login form to the -user. - -A "redirect" causes the browser to immediately fetch a different URL. This -process is usually not noticed by the user. - - -The URL table -------------- - -We need to construct a table describing the URLs used in our application. We -won't bother about the protocol part or any leading path segments of the URL. -In the table below, we'll assume all URLs start http://example.com/rosetta/... - -The table has the following columns - -- URL: The rest of the URL after /rosetta. For clarity, we'll start it with - a "./". So, the rosetta application's main page might be "./index.html". - If this table is written in HTML, this may be a link to a mock-up HTML page - showing what will be found at that URL. - -- Default: For application components, the default page to use. More about - this later. - -- Type: This is one of "app component", "page", "form", "redirect", "data" - -- Description: A textual description of what is found at this URL. - This may be a link to further information about the functioning of that - page, form validation constraints, and so on. - -When you get an App Component at a particular URL, what does that mean? At -certain points in our URL space, we want to expose a set of related -functionality under a particular URL. For example, the URL -"./projects/mozilla/show-teams" might show the teams working on the Mozilla -project, while "./projects/mozilla/translations" might show the translations -of the mozilla project. Users of the system will come to understand that -things related to Mozilla are to be found at URLs starting with -"./projects/mozilla". We want to present some page at "./projects/mozilla". -Rather than make a special "no name" page for this, we choose one of the -other pages that we want to return. Mozilla is a Project. So, if the -default page for a Project is "translations", then going to -"./projects/mozilla" will return the same page as -"./projects/mozilla/translations". The usual default page is "index.html". - - -Here's an example of a table for the Rosetta project:: - - URL Default Type Description - - ./ index.html app component The rosetta application - - ./index.html page Initial navigation page - - ./intro.html page Introductory page - - ./signup.html form Allows a new user to - register with the system. - - ./projects index.html app component Collection of rosetta - projects - - ./projects/index.html form Shows ways to search - through projects - - ./projects/$PROJECT translations app component A particular project - $PROJECT is the name of - the project. See key below. - - ./projects/$PROJECT/translations page Shows all translations - for this project. - - - Key to $VARs - ============ - $PROJECT The name of the project. This is the name attribute of - the IProjectGroup interface, or the name field in the Project - relation. Case is not significant, and is normalized to - lower-case in the UI. Examples: 'mozilla', 'gtk+'. - -We can use the URL table for simple automated functional testing of the web -application, given some suitable $VAR substitutions. - - -Structure of a web application URL ----------------------------------- - -We need to know what types of things are at a particular URL. Here's an -example of a typical URL in a web application. This time, I've included -the "rosetta" path segment at the root:: - - /rosetta/projects/$PACKAGENAME/teams/$TEAM/add-member.html - | | | | | | - | | | | | page to add a new member - | | | | Name of a particular team "22" - | | | The teams working on this project - | | A particular project name, such as "mozilla" - | Collection of projects that can be queried - The rosetta application - - -Guidelines for URLs -------------------- - -* Make your URLs from lower-case letters, numbers, '-' and '+'. - -* Avoid '_', capital letters, other symbols. - Using these things makes the URL harder to read out over the phone or - write down unambiguously. - -* When you have a collection of things, such as people or projects, use - a plural noun for that part of the URL. For example, "./projects". - -* Consider using "+" as the last URL segment for the URL that adds things - to a collection. For example, "./projects/+" to add a new project. - -* Where possible, use self-posting forms. So, you would go to the URL - "./projects/+" to get a form asking you for the information needed to - add a new project. When you submit the form, it POSTs to the same - URL. If the provided information is invalid, you'll get the form back - with an error message. Otherwise, you'll get a "success" message, or be - redirected to the next page in the workflow. - - - -Development iterations ----------------------- - -When you're developing a new system, don't try to write the whole table of -URLs at once. Instead, we can work in iterative cycles, designing pages -and URLs, and making these work in software. That way, we can learn earlier -on if the URLs and pages we want will actually work in practice. - -Here's the overall process of developing the application. - -Overall Process -~~~~~~~~~~~~~~~ - -1. Lay out the total functionality of the system, and divide it into a number - of iterations. -2. Pick the next iteration. Go through the Iteration Process described below. -3. Review / refactor the specification for previous iterations based on what - we learned during this iteration. -4. Refactor the whole application implemented so far to match the refactored - specification. - -Each iteration (that is, step 2 above) looks like this. - -Iteration Process -~~~~~~~~~~~~~~~~~ - -1. Write the URLs required for this iteration into the URLs table. - Ideally, there should be 3 to 7 URLs in each iteration. -2. Document the functionality required for each page. -3. Produce page template mockups. -4. Implement the functionality, using stub application components rather - than real application components. -5. Connect the functionality to the real database, by replacing the stubs - with real application components. - - -I will note that these processes are just guidelines on how to go about -writing the software. You might choose to prototype the application in -order to learn about what URLs are required for some tricky interaction. Or, -you might decide to write two iterations' worth of URLs into the URLs table -all at once, but then implement them in two iterations. The important thing -is to understand where you are in this process, and why you are doing what -you are doing at any particular stage. - -Keep the iterations short! - - -Glossary --------- - -Skin: - The way the user interface looks in a web browser. The elements of this - user interface, including CSS, images and an overall site template. - - It is possible to provide multiple skins to the same web application, - for example a simple one and a very complex one. - -Published: - Something that is made available at a particular URL is said to be - published. - -Presentation component: - Some software that interacts with the browser's request and returns - information to the browser. This is typically a page template or a - page template plus a supporting class. - - Other presentation components are traversers, which know what to do - when further path segments are given in a URL; and resources, which - are CSS files, javascript files, logos, icons, etc. - -Application component: - An object that represents application functionality, but not presentation - functionality. It should have a well-defined interface so that different - implementations of a given application component can be presented by - the same presentation components. - -Component: - An object that has clearly defined interfaces. - - These interfaces may represent what it offers, or what it requires in - order to function. - -Utility: - A component that is looked up by the interface that it provides. - -Adapter: - A component that knows how to use a particular interface in order to - provide a different interface. - -Interface: - A software-readable definition of an API provided by some object. - -View: - A kind of presentation component that provides a representation of - some other component. - -Browser presentation: - Presentation intended for a web browser, as distinct from a presentation - intended for XML-RPC or webdav. Or even email. - -Non-published {view,resource}: - A {view,resource} that is used by other presentation components, but - that is not itself addressable by a URL. - -Page: - An HTML document returned to a browser in response to a GET or POST - request to some URL. - -Form: - A page that contains HTML form elements and at least one "submit" - button. - -Self-posting form: - A form that's "action URL" is the same address that it was loaded from. - So, a form that was loaded from "./projects/+" would start:: - -
- - From 55009f7054095c9935d104bb1b343daa67141ef5 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 30 Sep 2024 21:26:31 +0200 Subject: [PATCH 10/21] comments addressed --- .wordlist.txt | 2 +- how-to/launchpad-api-docs.rst | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index 40c8034..96720e1 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -80,7 +80,7 @@ URL undercommunication updateable VM -xls +xsl xUnit XXXes YAML diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst index b8fbb00..c2502ce 100644 --- a/how-to/launchpad-api-docs.rst +++ b/how-to/launchpad-api-docs.rst @@ -15,7 +15,12 @@ generate the documentation under ``lib/canonical/launchpad/apidoc``. Note that we should delete the aforementioned folder in order to generate fresh docs. -The command above is responsible to call the +.. code-block:: bash + + $ rm -rf lib/canonical/launchpad/apidoc + $ make apidoc + +The command above is responsible for calling the ``utilities/create-lp-wadl-and-apidoc.py`` script and generate the related documentation using the ``lp.services.webservice.wadl`` module utilities. @@ -32,14 +37,14 @@ Example For example for the ``SocialAccount`` webservice we used the ``@exported_as_webservice_entry("social_account", as_of="beta")`` decorator. Thanks to that the ``social_account`` entry is created. -We can use the aforementioned id to refer this ``wadl`` entry in the ``wadl-to-refhtml.xls`` file. +We can use the aforementioned id to refer this ``wadl`` entry in the ``wadl-to-refhtml.xsl`` file. Let's say that we want to change the entry URL from ``URL: https://api.launchpad.net/beta/`` to ``URL: https://api.launchpad.net/beta//+socialaccount/``: we should create an entry inside the ``find-entry-uri`` template inside the -``wadl-to-refhtml.xls`` file and we should search our ``wadl`` entry using the -``social_account`` id. After that we can write ``xls`` code that will append the +``wadl-to-refhtml.xsl`` file and we should search for ``wadl`` entry using the +``social_account`` id. After that we can write ``xsl`` code that will append the right string to the ``$base`` URL: .. code-block:: html From 3833fdf5a70b8964842607d43088984a2e367743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Fri, 27 Sep 2024 17:17:47 +0200 Subject: [PATCH 11/21] Refine the debug buildfarm how-to --- how-to/debug-buildfarm-builder.rst | 58 +++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/how-to/debug-buildfarm-builder.rst b/how-to/debug-buildfarm-builder.rst index 00cee63..7fc7a93 100644 --- a/how-to/debug-buildfarm-builder.rst +++ b/how-to/debug-buildfarm-builder.rst @@ -1,30 +1,47 @@ -Debug Build Farm -================ +Debug Build Farm on qastaging +============================= -Access a builder in qastaging ------------------------------ +Access a builder +---------------- The builders are ephemeral, meaning they fully reset after a build. Therefore, to access the builder, one should either: * access it during the duration of a build. -* set the builder to ``manual`` after starting a build so that it doesn't +* ``disable`` the builder after starting a build so that it doesn't automatically trigger the reset when the build finishes. +.. note:: -Set a builder to manual -~~~~~~~~~~~~~~~~~~~~~~~ + You should wait until you see some output in the build log before you + ``disable`` the builder, otherwise the build might not get dispatched + properly. -This requires permissions granted by being part of the ``~admins`` team. -To anoint yourself to be part of that team in qastaging, see -:doc:`./manage-users`. -1. Go to https://qastaging.launchpad.net/builders. +Disable a builder +~~~~~~~~~~~~~~~~~ -2. Click on the builder you want to set to manual. +You need to have the ubuntu-archive-tools installed. -3. Click the "Switch to manual-mode" button. +.. code-block:: sh + + $ git clone https://git.launchpad.net/ubuntu-archive-tools + $ sudo apt install python3-launchpadlib python3-ubuntutools + + +For example, you want to debug the ``lcy02-amd64-004`` instance. + +.. code-block:: sh + + ❯ ./manage-builders -l qastaging -b qastaging-lcy02-amd64-004 --disable + Updating 1 builders. + * qastaging-lcy02-amd64-004 + Changed: 1. Unchanged: 0. + + +You can look up the builder name on https://qastaging.launchpad.net/builders or +via ``manage-builders -l qastaging``. SSH into the builder @@ -43,6 +60,8 @@ Once you are ready to access a builder, follow these steps: 4. SSH into builder instance. For example, to access the ``bos03-amd64-004`` builder, you should run ``ssh ubuntu@qastaging-bos03-amd64-004.vbuilder.qastaging.bos03.scalingstack``. + This builder address can be found when click on the builder on + https://qastaging.launchpad.net/builders. From there, you can check the ``launchpad-buildd`` logs in ``/var/log/launchpad-buildd/`` or run commands within the builder. @@ -51,3 +70,16 @@ The build itself should be done within a container within the builder. If you need to look into the container, you can ``lxc list`` to list the lxc containers present in the builder, and then run ``lxc shell`` to start a shell session from within the container. + + +Clean-up +~~~~~~~~ + +Once you have finished, please remember to enable the builder again. + +.. code-block:: sh + + ❯ ./manage-builders -l qastaging -b qastaging-lcy02-amd64-004 --enable + Updating 1 builders. + * qastaging-lcy02-amd64-004 + Changed: 1. Unchanged: 0. From fdda4ed8f0689ad256a8a353d1c86b5d3a72f17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Sat, 28 Sep 2024 13:00:14 +0200 Subject: [PATCH 12/21] Handle links to flaky cgit website --- custom_conf.py | 1 + reference/services/git-hosting.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_conf.py b/custom_conf.py index c36f640..ed724c2 100644 --- a/custom_conf.py +++ b/custom_conf.py @@ -141,6 +141,7 @@ r'https://github\.com/canonical/fetch-service*', # private r'https://github\.com/canonical/fetch-operator*', # private 'https://git.launchpad.net/charm-launchpad-buildd-image-modifier/tree/files/scripts/setup-ppa-buildd', # private + 'https://git.zx2c4.com/cgit/', # unfortunately very flaky ] # Pages on which to ignore anchors diff --git a/reference/services/git-hosting.rst b/reference/services/git-hosting.rst index 77fa659..cb40b5e 100644 --- a/reference/services/git-hosting.rst +++ b/reference/services/git-hosting.rst @@ -58,7 +58,7 @@ Code that is executed as part of the Launchpad web application. Major features: Repository source code browser ------------------------------ -Launchpad uses the external `cgit `_ project to provide a web view of the repository contents. +Launchpad uses the external `cgit `_ project to provide a web view of the repository contents. This is invoked by ``turnip`` when it receives HTTPS requests that don't correspond to git smart HTTP protocol, and ``turnip``` deals with configuring ``cgit`` appropriately for each repository. From d1379989fd875e5c07258d020b592f7e0d842595 Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 4 Oct 2024 15:19:27 +0200 Subject: [PATCH 13/21] address comments --- how-to/launchpad-api-docs.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst index c2502ce..9980d98 100644 --- a/how-to/launchpad-api-docs.rst +++ b/how-to/launchpad-api-docs.rst @@ -12,8 +12,11 @@ the related documentation for the exported field. We can build Api Docs using ``make apidoc`` command: this command will generate the documentation under ``lib/canonical/launchpad/apidoc``. -Note that we should delete the aforementioned folder in order to generate -fresh docs. + +.. note:: + + Note that we should delete the aforementioned folder in order to generate + fresh docs. .. code-block:: bash @@ -24,7 +27,7 @@ The command above is responsible for calling the ``utilities/create-lp-wadl-and-apidoc.py`` script and generate the related documentation using the ``lp.services.webservice.wadl`` module utilities. -This scripts will create the related ``wadl`` and then it will translated to +This script will create the related ``wadl`` file and then it will translated to ``HTML``. During this process ``generate_html`` function will be called: this function is responsible to map ``wadl`` entries to ``HTML``. To do that we use as template the file called ``wadl-to-refhtml.xsl``: in From 137f067827dcc04d34577d3274bb75772fd94315 Mon Sep 17 00:00:00 2001 From: Simone <9490772+simonepelosi@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:19:49 +0200 Subject: [PATCH 14/21] Update how-to/launchpad-api-docs.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jürgen Gmach --- how-to/launchpad-api-docs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst index 9980d98..39ca046 100644 --- a/how-to/launchpad-api-docs.rst +++ b/how-to/launchpad-api-docs.rst @@ -30,7 +30,7 @@ documentation using the ``lp.services.webservice.wadl`` module utilities. This script will create the related ``wadl`` file and then it will translated to ``HTML``. During this process ``generate_html`` function will be called: this function is responsible to map ``wadl`` entries to ``HTML``. -To do that we use as template the file called ``wadl-to-refhtml.xsl``: in +For that we use ``wadl-to-refhtml.xsl`` template. In this file we can also apply patches to fix not-well generated entry points for given ``wadl`` entries. From 0ad31a6f85528fa1f888a1a0df4bb93bffb458e7 Mon Sep 17 00:00:00 2001 From: Simone <9490772+simonepelosi@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:19:55 +0200 Subject: [PATCH 15/21] Update how-to/launchpad-api-docs.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jürgen Gmach --- how-to/launchpad-api-docs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst index 39ca046..becfbf3 100644 --- a/how-to/launchpad-api-docs.rst +++ b/how-to/launchpad-api-docs.rst @@ -8,7 +8,7 @@ web service versions, and links to version-specific documents. To define our web resources we are using the `lazr.restful `_ decorators and capabilities. These decorators are also responsible to generate -the related documentation for the exported field. +the related documentation for the exported fields. We can build Api Docs using ``make apidoc`` command: this command will generate the documentation under ``lib/canonical/launchpad/apidoc``. From 3b562d9d4dc623fb45d6ad4685bcfe52af7af790 Mon Sep 17 00:00:00 2001 From: Simone <9490772+simonepelosi@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:20:00 +0200 Subject: [PATCH 16/21] Update how-to/launchpad-api-docs.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jürgen Gmach --- how-to/launchpad-api-docs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst index becfbf3..8b04189 100644 --- a/how-to/launchpad-api-docs.rst +++ b/how-to/launchpad-api-docs.rst @@ -10,7 +10,7 @@ To define our web resources we are using the decorators and capabilities. These decorators are also responsible to generate the related documentation for the exported fields. -We can build Api Docs using ``make apidoc`` command: this command will +We can build API docs using ``make apidoc`` command: this command will generate the documentation under ``lib/canonical/launchpad/apidoc``. .. note:: From 1e9d7bfd5ae2d7eb428ce6f788c8a4e5679b420f Mon Sep 17 00:00:00 2001 From: Simone <9490772+simonepelosi@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:20:06 +0200 Subject: [PATCH 17/21] Update how-to/launchpad-api-docs.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jürgen Gmach --- how-to/launchpad-api-docs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst index 8b04189..1668376 100644 --- a/how-to/launchpad-api-docs.rst +++ b/how-to/launchpad-api-docs.rst @@ -24,7 +24,7 @@ generate the documentation under ``lib/canonical/launchpad/apidoc``. $ make apidoc The command above is responsible for calling the -``utilities/create-lp-wadl-and-apidoc.py`` script and generate the related +``utilities/create-lp-wadl-and-apidoc.py`` script and generating the related documentation using the ``lp.services.webservice.wadl`` module utilities. This script will create the related ``wadl`` file and then it will translated to From 650fa8ef93cf55713c98392415489fea0ce13952 Mon Sep 17 00:00:00 2001 From: Simone <9490772+simonepelosi@users.noreply.github.com> Date: Sat, 5 Oct 2024 14:34:52 +0200 Subject: [PATCH 18/21] Update how-to/launchpad-api-docs.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jürgen Gmach --- how-to/launchpad-api-docs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/how-to/launchpad-api-docs.rst b/how-to/launchpad-api-docs.rst index 1668376..2aa8e54 100644 --- a/how-to/launchpad-api-docs.rst +++ b/how-to/launchpad-api-docs.rst @@ -27,7 +27,7 @@ The command above is responsible for calling the ``utilities/create-lp-wadl-and-apidoc.py`` script and generating the related documentation using the ``lp.services.webservice.wadl`` module utilities. -This script will create the related ``wadl`` file and then it will translated to +This script will create the related ``wadl`` file and translate it to ``HTML``. During this process ``generate_html`` function will be called: this function is responsible to map ``wadl`` entries to ``HTML``. For that we use ``wadl-to-refhtml.xsl`` template. In From 5e66b010a003c2f726c1135b8946e5e9697af482 Mon Sep 17 00:00:00 2001 From: Ines Almeida Date: Tue, 8 Oct 2024 16:42:54 +0200 Subject: [PATCH 19/21] Add details about adding LPCONFIG env variable when running scripts --- how-to/manage-users.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/how-to/manage-users.rst b/how-to/manage-users.rst index 5a44beb..26367c4 100644 --- a/how-to/manage-users.rst +++ b/how-to/manage-users.rst @@ -52,3 +52,13 @@ In our example: .. code:: /srv/launchpad/code/utilities/anoint-team-member test-user admins + +.. note:: + + Note that for running some of these scripts, it is common to need to add a + ``LPCONFIG=launchpad-admin`` at the start of the command to set the needed + evironmental variable. This is not necessary here because it is already + set in the environment within the ``launchpad-admin`` unit. + Running this command in another unit (for example, ``launchpad-scripts``) + would require running as ``LPCONFIG=launchpad-admin + /srv/launchpad/code/utilities/anoint-team-member ``. From eaaadc43362fa957b98d38ff17f980af24eca12a Mon Sep 17 00:00:00 2001 From: Ines Almeida Date: Tue, 8 Oct 2024 16:44:21 +0200 Subject: [PATCH 20/21] Add details about applying a specific schema change locally --- how-to/apply-schema-changes.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/how-to/apply-schema-changes.rst b/how-to/apply-schema-changes.rst index 98542e0..b10a7f8 100644 --- a/how-to/apply-schema-changes.rst +++ b/how-to/apply-schema-changes.rst @@ -40,3 +40,13 @@ please run the following command: .. code-block:: bash make -C database/schema test + +If you only want to apply one specific patch for testing purposes, you can +run the following command: + +.. code-block: bash + + psql launchpad_dev -1 -f .sql + +This comment will apply file (``-f``) ``.sql`` as a single +transaction (``-1``) to the database named ``launchpad_dev``. From d3071408622fdbd7ca4ebd871c3ae0e369c67167 Mon Sep 17 00:00:00 2001 From: Ines Almeida Date: Wed, 9 Oct 2024 13:02:33 +0200 Subject: [PATCH 21/21] Fix typo in how-to/manage-users --- how-to/manage-users.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/how-to/manage-users.rst b/how-to/manage-users.rst index 26367c4..96f35c8 100644 --- a/how-to/manage-users.rst +++ b/how-to/manage-users.rst @@ -57,7 +57,7 @@ In our example: Note that for running some of these scripts, it is common to need to add a ``LPCONFIG=launchpad-admin`` at the start of the command to set the needed - evironmental variable. This is not necessary here because it is already + environmental variable. This is not necessary here because it is already set in the environment within the ``launchpad-admin`` unit. Running this command in another unit (for example, ``launchpad-scripts``) would require running as ``LPCONFIG=launchpad-admin